MAMS Gaming said: timmaugh said: If you use TokenMod for this, as Oosh suggested, you could augment that with a metascript mule to give you the same 3 ranges of green, yellow, and red. Feed the quotient of the current hits / max hits to the mule, and return arguments for the token mod statement. I understood very little of that. I should point out that I'm very new to this. I only taught myself js to be able to play with Roll20. You did bring up how I am defining my ranges. I'm using the same code as the character sheet: // Define Yellow Max & Red Max (*1 ensures token_hp_max is treated as a number)
var token_yellow_max = (Math.round((token_hp_max*1+2)*0.7));
var token_red_max = (Math.round((token_hp_max*1+2)/3));
if (token_hp_max === 37) {
var token_yellow_max = 28;
} else if (token_hp_max === 19) {
var token_yellow_max = 14;
} No worries, MAMS. Here's a primer on the metascript toolbox . The basic idea is that they get into the command line sent to other scripts (or standard chat messages) to give you more flexibility to have that command line adapt to the current state of the game. To demonstrate your need, I'll start small and build out from there. The Goal First, as I understand it, your goal is to have only one of the bars of the token to be visible at a time. Dividing the range of 100% of current HP into 3 ranges, then, means that you would have bar 1 (the green bar) visible for an hp percentage over 66%, and bar 3 (the red bar) visible for any hp percentage under 34%. (Those numbers are easily changed; you'll see in a minute.) As Oosh said, TokenMod can do this for you, but what you're lacking is the ability of that one TokenMod command line to adapt to the current situation of the token/character. You don't want 3 different TokenMod commands with you having to select which one to run; you want a single command line that detects the state of things and makes the correct adjustment to the token's bars. The Base Command The TokenMod command that we'll modify would look like this for making bar 1 visible and represent the attribute "hp": !token-mod --set bar1_link|hp bar2_link| bar3_link| bar2_max|x bar3_max|x That links the first bar, unlinks the other two, and sets the "max" values of the bars we want to hide to be "x". There would be another option for making bar 2 visible, and a third option for bar 3. Using a Mule as an Off-Loaded Case Test One thing about the Muler script is that it's structure allows for it to use the variables housed in a Mule as a way to off-load case tests from a macro. It could make a macro very hard to read if you had to account for 20 different possible cases in the text of the macro, itself -- if you even could, with no if/then logic available from Roll20 syntax or case testing aside from some creative inline roll manipulation. A Mule has a list of variables that will return input to the command line, and they can be constructed as numeric ranges to allow for finding a result easily. In your case, we need three entries: less than 34, between 34 and 66, and greater than 66 (again, you can move those numbers to adjust your ranges). So we set our Mule up like this: <34= ... 34-66= ... >66= ... If we feed it a range under 34, we'll get the value we put to the right of the = sign. What is the thing that we will feed? The percentage of current HP out of Max HP, expressed as a range of 0 to 100: [[floor((@{selected|hp}/@{selected|hp|max})*100)]] One thing about inline rolls and metascripts is that metascripts only mess with the command line where you tell them to. In other words, they don't unpack a given inline roll unless you want them to. If you do nothing, the roll will pass through to be dealt with by the receiving script (in this case, TokenMod, which handles its own inline-roll-unpacking). We need the value before the message gets to TokenMod, so we have to extract the value of the inline roll so that we can feed it to the Mule. We do that by adding .value to the end of the inline roll (a ZeroFrame syntax structure). [[floor((@{selected|hp}/@{selected|hp|max})*100)]].value Now we know if the character has 10 out of 20 HP, the value of the roll will be 50, and 50 should fall into that middle line of the Mule. Loading the Mule and Retrieving the Value A mule is loaded using the {&mule} statement, and variables are retrieved with a get.../get. So let's say the Mule (ability) is named "HealthIndicators" and the mule-character housing that ability is called "MuleBoy". The {&mule} statement would look like this: {& mule MuleBoy.HealthIndicators} ...and our get statement, using the roll we just established, would look like this: get.MuleBoy.HealthIndicators.[[floor((@{selected|hp}/@{selected|hp|max})*100)]].value/get The {&mule} syntax can go anywhere in the macro and be detected. The get statement will return the value of the variable from the Mule, so we definitely want it in the right place. What it needs to return is the different TokenMod command line variations depending on those three levels. So, taking another look at the Mule, the full structure have the appropriate TokenMod syntax as the returned value for each level. <34=bar3_link|hp bar2_link| bar1_link| bar2_max|x bar1_max|x 34-66=bar2_link|hp bar1_link| bar3_link| bar1_max|x bar3_max|x >66=bar1_link|hp bar2_link| bar3_link| bar2_max|x bar3_max|x Sub-Finalized Command Line What we're retrieving are the component parts of the TokenMod --set argument, so we make sure the Muler get statement is in that position in our Token-Mod command line, and we arrive at our command line of: !token-mod --set get.MuleBoy.HealthIndicators.[[floor((@{selected|hp}/@{selected|hp|max})*100)]].value/get {&mule MuleBoy.HealthIndicators} Running that for a Token will apply the correct linkages and values to make the appropriate bar visible. The above command will work for a single token selected. REQUIRED SCRIPTS: TokenMod, ZeroFrame, Muler Hydrate This is your friendly, neighborhood MetaMancer letting you know it's time to hydrate. You've been at this a while, and we're about to initiate you into the deeper meta-mancery. ...There. Feeling better? Let's continue. Taking It Further TokenMod works on the selected tokens OR on token ids fed to the --ids argument. So you could feed multiple token IDs to the command line, except that the way the above roll math is constructed, everyone will have the same bar visible, no matter the state of the HP % (the selected-hp and selected-hp-max are pulled one time by Roll20 before the API gets involved, the math is performed, and the result is then used by TokenMod for all tokens it should affect). We want differentiated results for each token. We can achieve that by adding SelectManager and Fetch to our metascript toolbox. forselected SelectManager gives us a forselected handle that iterates an API command over the set of selected tokens. Just by pre-pending a script command line with forselected, you will send that command through one time for every selected token, and for each resulting message there will be only one token selected (first token1, then token2, etc.). !forselected token-mod --set ... That doesn't change the fact that the math is done already. For that we need Fetch. Fetch Fetch lets us get data from the selected token (or a token by id or name, a character sheet, or the speaker) after Roll20 parsing is done, but before standard scripts get involved. Fetch constructions look a lot like standard Roll20 constructions, just with parentheses instead of braces. Also, you can use periods rather than pipes -- which I often do just to clue the eye in to the fact that this is a Fetch call, not a standard R20 construction: @(selected.hp) @(selected.hp.max) Timing So far we've got our initial message sending out a message for each token selected. We want to hold off on the parser "discovering" our Fetch construction until those secondary messages go out. Remember, each of those messages has a different selected token, so our Fetch constructions (reading from the selected token) will return differentiated data. If we let the Fetch constructions be detected in the first message, we'll be back in the same boat we were at the beginning, with a single value being retrieved and the math being performed prior to sending out our various TokenMod messages (every token will display its HP in the bar designated by the math performed on the values of the FIRST selected token). We call delaying the discovery of a metascript construction "deferring", and we can defer constructions in a forselected statement by designating a deferral character. I often use a caret (^), unless the downstream command line actually would need/use that character... then I might use a † (alt-0134 on a Windows machine), or a ‡ (alt-0135). You declare it like this: !forselected(^) ... Now we can use that to break up the downstream constructions we don't want to have detected until we are in the messages forselected dispatches. @^(selected.hp) @^(selected.hp.max)
{^& mule ...}
get^.HealthIndicators... Timing Part Deux If you're paying attention, those Fetch constructions are inside an inline roll: [[floor((@(selected.hp)/@(selected.hp.max))*100)]] Inline rolls are parsed by Roll20 before metascripts can get in there to provide those values, so if we leave things like this, the inline roll will break with bad syntax. That means now that we have subbed in Fetch constructions for the standard Roll20 attribute calls, we have to defer the inline rolls. For a normal Fetch construction in a normal roll in a normal message, that would mean utilizing [\][\]...\]\] syntax for the inline roll: [\][\]floor((@(selected.hp)/@(selected.hp.max))*100)\]\] In your case, with the Fetch construction already being deferred until the secondary message dispatched by forselected , we have to ALSO defer our (already-deferred) inline rolls UNTIL that message: [\^][\^]floor((@^(selected.hp)/@^(selected.hp.max))*100)\^]\^] Sub-Finalized Command Line With the appropriate deferrals giving us token-specific data at the time that the scripts need it, our command line now looks like this: !forselected(^) token-mod --set get^.MuleBoy.HealthIndicators.[\^][\^]floor((@^(selected.hp)/@^(selected.hp.max))*100)\^]\^].value/get {^&mule MuleBoy.HealthIndicators} That will work for multiple tokens selected, giving you differentiated results for each. REQUIRED SCRIPTS: TokenMod, ZeroFrame, Muler, Fetch, SelectManager Letter Home from MetaScript Camp Hi, mom... It's my first day at metascript camp and I already hate it. My instructor is so mean. He made us do compounded deferrals in our very first session. We were metamancing so hard, the kid next to me vomited. I want to come home. --Your Kid (if loving parents actually send their own kids to a hell-hole like this) Taking It Further-er So far, we've built our command line around having the token(s) actually selected on the VTT. This can be even more hands-off if you use the SelectManager method of virtually selecting the tokens: {& select token_id 1 , token_id 2 , Token Name 1 , Token Name 2 , ... } That construction overwrites the set of selected tokens from the tabletop (without actually changing the selection status of anything on the board) with the list you specify. As far as the message is concerned, the list you provide is the set of tokens selected (provided they all map to a token the script can locate). So you could provide the list of tokens you want to manipulate, making sure that list represents the tokens in combat at the time: {&select Cuddles, Glarg, Bubbles Magoo, Biddy the Kill} Then your forselected statement would iterate over that list of tokens, dispatching the relevant TokenMod command with the appropriate data for each. You could keep that list on a character sheet (say, on the same MuleBoy character already referenced) and retrieve it with an attribute call: {&select @{MuleBoy|TokensInCombat} } (I'm currently working on a Query metascript that would let you select your tokens even more dynamically than this, but it's not ready/released yet.) Relatively-Finalized Command Line The {&select} syntax can be placed anywhere in the command line. We don't defer it, because we want it detected prior to the messages being dispatched to TokenMod: !forselected(^) token-mod --set get^.MuleBoy.HealthIndicators.[\^][\^]floor((@^(selected.hp)/@^(selected.hp.max))*100)\^]\^].value/get {^&mule MuleBoy.HealthIndicators} {&select @{MuleBoy|TokensInCombat} } That will iterate the TokenMod command over the tokens listed (comma-separated) in the attribute retrieved from the MuleBoy character. You will NOT have to select them on the VTT. REQUIRED SCRIPTS: TokenMod, ZeroFrame, Muler, Fetch, SelectManager Final Considerations That's a pretty powerful statement, but it does come with the caveats that (1) you have to run it manually, and (2) it is only for tokens with the given attribute you are trying to map to the bars... that is, if your characters have HP but your NPCs have "npc_hp", the line will need more tweaking to include NPCs and characters in the same macro processing. That could be accomplished by incorporating APILogic (another metascript) syntax in the value retrieved from the Mule, but I've already had half the kids leave MetaScript Camp at this point, so I'll just point out that this is available, at this point. Short of using that method, you could have a macro for characters and a separate one for NPCs (if you wanted/needed to affect both). As for running it manually, this is where you could either code a listener to fire off this macro, or you could use Customizable Roll Listener to listen for attack template verbiage, and fire off this script automagically. That would require more testing.