Sihr said:
timmaugh said:
Are scripts available, or no?
BTW, you can include template things in a query with the proper HTML substitutions, no problem. Script availability might just make this easier, though.
I have no idea what you're referring to with scripts. If there's a better way to do this, I'm all ears.
You're saying I can insert a template into the query with no problem. Well, I've found problems. Lots of problems. Are you sure that it would work?
Hey, Sihr. I may have mispoke about the template parts in a query. I can't find any of my former examples of what I thought I'd been able to do, so I'll have to dig into this more to remember where the boundaries are and what the tricks are to get around them.
However.
You've gotten a lot of help on the template front, so I want to concentrate on some of the other deficits you've alluded to.
Scripts
First "scripts" (or, "mod scripts") are community-written add-ons that you can implement in your game. They are a perk of being a Pro subscriber, but they are available for everyone in a game created by a Pro-sub. In other words, if your game's creator is a Pro subscriber, then scripts are available to you; a GM will just have to install them in the game for you.
You may have heard of some of the more popular scripts if you've been around the forums or discord for long, or if you've watched some of Nick Olivo's YouTube videos. Names like TokenMod, ChatSetAttr, GroupInit, GroupCheck, ScriptCards, SmartAoE, and the MetascriptToolbox (among others) are all system-agnostic scripts, so you can use them no matter the system you're running. Other scripts are more specifically tailored to some particular rule of a particular system, and so don't necessarily make sense to use in other games.
I mentioned scripts because the MetascriptToolbox and ScriptCards both offer ways to implement logical constructions in your command line and output contingent result panels... they just do it in slightly different ways. Being a software dev, yourself, you might enjoy ScriptCards, as it is built to emulate a command language you can input directly from chat (ie, from an ability or macro). However, the Toolbox was written to interact with (and augment) other scripts (or to just output panels directly to chat without the need of other scripts), so the two packages are fundamentally different.
As the author of the Toolbox, I'll explain how it can help with what you're trying to do.
Timing
If you're new to writing macros for Roll20 and especially if you're new to using scripts on Roll20, I'd recommend watching this video. Well, if you're going to go on to use metascripts, watch the whole thing. If you're only going to be using standard macro syntax and standard scripts, you only have to watch the first ~15 minutes (the first 2 parts). That explains how things generally work.
Metascript Trinkets and Doodads
You mentioned wanting logical IF structures and decision tree mapping. Metascripts can do this for you. They can let you reuse queries for multiple purposes, reuse rolls even outside of nested roll structures, run batches of commands together to share rolls across the messages, build templates out of looped output, implement global variables to let you re-reference data later, directly access game data beyond what Roll20 native syntax structures expose for you... lots of things.
And, since it can do all of this, you don't have to necessarily nest queries (unless you wanted to in order to limit the number of things you have to answer).
For instance, a simple IF logical structure:
{&if ?{Rage} = yes}Raging{&else}Not raging{&end}
Now put it in a message that will hit the chat:
!You answered the query with ?{Rage|Yes|No}. The IF block resolves to: {&if ?{Rage} = yes}Raging{&else}Not raging{&end}.{&simple}
A simple reference to a sheet attribute for the selected token:
@(selected.Rage)
Put into a message that will hit the chat:
!The selected character has a Rage value of @(selected.Rage).{&simple}
And combine the methods to drive a logical evaluation based on the result being a 0 or 1:
!The selected character is {&if @(selected.Rage) = 0}NOT {&end}raging. {&simple}
IF structures allow ELSEIF and ELSE cases, as well as chaining logical tests for more complex trees:
{&if a = b || b = c || (a = c && d != e)}True case{&elseif a > b && a > c}Else if case{&else}Else case{&end}
They also allow nesting:
{&if a = b} {&if c > d}Nested true case{&else}Nested else case{&end} {&else}Outer Else case{&end}
A lookup on a mule ability:
get.MuleCharacter.MuleAbility.variableName/get
...which could be a number:
get.MuleCharacter.MuleAbility.1/get
...which means it could be the result of a roll:
get.MuleCharacter.MuleAbility.$[[0]].value/get
...and the same can be done from a rollable table:
@(table.TableName.$[[0]].value)
How it helps you
You can use any/all of these structures in a template command that you output to chat. And you can use these tricks (and more) to manipulate rolls, repackage values, and build outcome sets. For instance, you could use queries to drive usage case, then have nested IF structures or chained-evaluation to drive results. Chained evaluation:
!&{template:default}{{name=Proof of Concept}} {{Rage Query=?{Rage|Yes|No} }} {{Savage Attacker Query=?{Savage|Yes|No} }} {{Magic Weapon Query=?{Magic Weapon|Yes|No} }} {{Result={&if ?{Rage} = Yes && ?{Savage} = Yes && ?{Magic Weapon} = Yes}All 'Yes' result{&elseif ?{Rage} = Yes && ?{Savage} = Yes && ?{Magic Weapon} = No}Yes for Rage and Savage, No to Magic Weapon{&else}Delineate/expand other cases here{&end} }}{&simple}
Nested structures:
!&{template:default}{{name=Proof of Concept}} {{Rage Query=?{Rage|Yes|No} }} {{Savage Attacker Query=?{Savage|Yes|No} }} {{Magic Weapon Query=?{Magic Weapon|Yes|No} }} {{Result=
{&if ?{Rage} = Yes}
{&if ?{Savage} = Yes}
{&if ?{Magic Weapon} = Yes}
All 'Yes' result
{&else}
Yes for Rage and Savage, No to Magic Weapon
{&end}
{&else}
{&if ?{Magic Weapon} = Yes}
Yes for Rage and Magic Weapon, No to Savage
{&else}
Yes for Rage, No to Savage and Magic Weapon
{&end}
{&end}
{&else}
Duplicate/delineate results now for the No response to Rage query
{&end}
}}{&simple}
(That one may include extra line breaks since I wrote it to span multiple lines.)
If it were me...
If I was dealing with this, I think I would use exponential binaries to represent my cases:
CONDITION | BINARY EXPONENT | VALUE |
---|
Rage | 2^0 | 1 |
Savage Attacker | 2^1 | 2 |
Magical Weapon | 2^2 | 4 |
(If you wanted another case in there—ie, necrotic vs radiant—you'd just have another on/off and adjust your exponent assignments as necessary.)
At this point, you'd only have to total your condition values to know your case:
0=None
1=Rage
2=Savage Attacker
3=Rage + Savage Attacker
4=Magical Weapon
5=Rage + Magical Weapon
6=Savage Attacker + Magical Weapon
7=Rage + Savage Attacker + Magical Weapon
So you could have a mule ability setup to represent those cases, including the verbiage you need. Just copying from a previous post of yours, I think that would look like:
0=[[2d6+4]] bludgeoning
1=[[2d6+6]] bludgeoning, [[1d6+2]] radiant
2=[[{2d6,2d6}kh1+4]] bludgeoning
3=[[{2d6,2d6}kh1+6]] bludgeoning, [[1d6+2]] radiant
4=[[2d6+4]] bludgeoning, [[2d6]] fire
5=[[2d6+6]] bludgeoning, [[1d6+2 radiant, [[2d6]] fire
6=[[{2d6,2d6}kh1+4]] bludgeoning, [[2d6]] fire
7=[[{2d6,2d6}kh1+6]] bludgeoning, [[1d6+2]] radiant, [[{2d6,2d6}kh1]] fire
Enter that text into an ability called (let's say) DamageCase on a character named TableMule. Now you can produce your output as:
!&{template:default} {{name=Test With Ability}} {{attack= %{Character_Name|attack} }} {{damage= get.TableMule.DamageCase.[[?{Rage|No,0|Yes,1} + ?{Savage|No,0|Yes,2} + ?{Magical Weapon|No,0|Yes,4}]].value/get }}{&simple}
Now with 100% less queries
The same thing can be obtained from character sheet attributes (if they are available). Since you can create attributes for each of these if they don't exist, let's just say they're available.
If the attributes are named "Rage", "Savage", and "MagicWeapon" (to represent if these cases are in use/equipped)...
...AND...
...if the attributes are valued at a 0 or 1 (the default for checkboxes on a sheet)...
Then your case derivation can be changed to:
get.TableMule.DamageCase.[[@{CharacterName|Rage} + (@{CharacterName|Savage} * 2) + (@{CharacterName|MagicalWeapon} * 4)]].value/get
Swap that into the command line, above, and you'll get the same thing, just without having to answer queries.
Other Approaches
If the attributes on the sheet are not 0/1 based but are instead governed by what you put there (for instance, with another script like ChatSetAttr), then all of that can be combined into a set of control macros that set the appropriate values as they would occur in the course of the game (or even at the moment that the attack is made). For instance, you could be putting 0/1, 0/2, and 0/4 for the values as appropriate. All of this can be combined into the single, metascript-powered command line...
...but...
Since you have purposefully reduced this to an x/y problem, and since it is really an x^z/y problem (where I have no way of knowing all of the potential x-cases that could arise which could conceivably be described as a "it's generally y" situation), I'm not going to get crazy with the Cheez Whiz and try to solve them all.
You asked for a better way. This is a better way. I'll leave it to you to ask more elucidating questions at this point, if scripts are available.
REQUIRED SCRIPTS:
MetascriptToolbox