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 Compendium in Game, Join Today

ChatSetAttr Evaluate Syntax Help

I'm using the 5th Edition OGL Character sheet.  What I'd like to do is use ChatSetAttr to compare the attributes of an NPC to the corresponding attributes of a named PC character and potentially make changes to the NPC's attributes based on the results.  I'm not sure if what I'm attempting is beyond the scope of the evaluate function (given the very different potential contents of the attributes involved) or if I'm simply not getting the syntax right. For the specific use example below, the starting values of the attributes are: For NPC: pb_custom = 2 npc_str_save_flag = 0 npc_con_save_flag = 0 For Snow White: pb = 3 strength_save_prof = 0 con_save_prof = (@{pb}) which evaluates to (3) in chat results When I try this: !setattr {{ --sel --evaluate --pb_custom| (%pb_custom% < @{Snow White|pb}) ? @{Snow White|pb} : %pb_custom% --npc_str_save_flag| (@{Snow White|strength_save_prof} > 0) ? 1 : %npc_str_save_flag% --npc_con_save_flag| (@{Snow White|constitution_save_prof} > 0) ? 1 : %npc_con_save_flag% }} It works for the proficiency bonus part: Setting attributes Setting pb_custom to 3 for character Copy of Animal Testing. However it doesn't work for the others, giving these errors: Errors Something went wrong with --evaluate for the character Copy of Animal Testing. You were warned. The error message was: SyntaxError: Unexpected end of input. Attribute npc_con_save_flag left unchanged. Something went wrong with --evaluate for the character Copy of Animal Testing. You were warned. The error message was: SyntaxError: Unexpected end of input. Attribute npc_str_save_flag left unchanged. I get the same error even if I manually change the con_save_prof attribute to a plain 3.  I also get it when trying different comparison operators such as: !setattr {{ --sel --evaluate --pb_custom| (%pb_custom% < @{Snow White|pb}) ? @{Snow White|pb} : %pb_custom% --npc_str_save_flag| (@{Snow White|strength_save_prof} !== 0) ? 1 : %npc_str_save_flag% --npc_con_save_flag| (@{Snow White|constitution_save_prof} !== 0) ? 1 : %npc_con_save_flag% }} Can anyone point out where I'm making mistakes and a solution that might work?
1577481165
GiGs
Pro
Sheet Author
API Scripter
I havent used evaluate before, but the syntax looks the same in each. Have you tried removing the multiple changes, and just trying once in each macro, to see if each work. The fact that the first works, but those after it, makes me wonder. So, like, try each of !setattr {{ --sel --evaluate --pb_custom| (%pb_custom% < @{Snow White|pb}) ? @{Snow White|pb} : %pb_custom% }} !setattr {{ --sel --evaluate --npc_str_save_flag| (@{Snow White|strength_save_prof} > 0) ? 1 : %npc_str_save_flag% }} !setattr {{ --sel --evaluate --npc_con_save_flag| (@{Snow White|constitution_save_prof} > 0) ? 1 : %npc_con_save_flag% }} Just to check if those operations do work on their own. If they dont. might need to look at the stat values and see if there's anything special about them.
The only one that works on its own is the pb attribute one that works even bundled with the others.  The others don't function in isolation. The constitution_save_prof is the only one that's not an integer, so I'd expect it to give some type of trouble, but I'm not sure why the strength_save_prof works differently than the pb one.
1577617606
Jakob
Pro
Sheet Author
API Scripter
I don't really know what's up, but try setting some dummy attribute to the same value without --evaluate in order to see what kind of expression it's trying to evaluate. If you see that, it may become obvious why there's a syntax error.
Jakob said: I don't really know what's up, but try setting some dummy attribute to the same value without --evaluate in order to see what kind of expression it's trying to evaluate. If you see that, it may become obvious why there's a syntax error. Every time I test this, I do it on a fresh copy of a testing sheetso I can easily compare it to the original.  So rather than following the letter of your suggestion, I followed the spirit of it and got a strange result. The original character sheet has a npc_str_save_flag attribute with a value of 0. On the copy, I ran the following: !setattr {{ --sel --npc_str_save_flag| %npc_str_save_flag% }} And got the result: Setting attributes Setting npc_str_save_flag to for character Copy of Animal Testing. So the npc_str_save_flag started at 0, but ended up blank somehow. When I tried setting npc_str_save_flag to 1, that worked as expected, giving a value of 1.  When I tried setting npc_str_save_flag to @{Snow White|strength_save_prof} that worked as expected, giving a value of 0. 
1577651337

Edited 1577656619
Some more trouble-shooting tries... I just made a fresh copy of the original character, selected it, and entered @{selected|npc_str_save_flag} in chat which gave an expected result of 0.  When I tried: !setattr {{ --sel --dummy| %npc_str_save_flag% }} It created the dummy attribute with what looks to be a blank value instead of 0.  Setting attributes Setting dummy to for character Copy of Animal Testing. Examining the dummy field on the character sheet more closely, I found I can select what appears to be a single space (which isn't the case for the other blank attribute fields). Now entering something like the below into chat: @{selected|ac}@{selected|ac}@{selected|dummy}@{selected|ac} Yields a chat result of: 1111 11 But if I instead use the npc_str_save_flag attribute from which the dummy attribute was made: @{selected|ac}@{selected|ac}@{selected|npc_str_save_flag}@{selected|ac} I get a chat result of: 1111011 I experimented a little bit with other "blank" attribute fields in the character sheet and found that some seemingly blank fields will return values in chat.  For instance, entering: @{selected|npc_str_save} @{selected|npc_survival} Gives a chat result of: 1 0 Those numbers are consistent with the character's corresponding Strength and Wisdom bonuses that would be used to calculate those fields, so it seems the "blank" fields somehow have their contents hidden, possibly by their respective flag field values (though entering a value greater than 0 in the flag field doesn't seem to reveal the other value). In short, I'm still stuck on what I want to accomplish.  Essentially, I want to be able to determine which skills/saves an npc character is proficient in, add any additional skill/save proficiencies that a particular PC character has, and then assign newly calculated values only to those skill/save attributes for which proficiency exists.  Maybe I need to mine proficiency information from somewhere else on the 5th Edition OGL Character sheet and create placeholder attributes to accomplish what I want. edit: Just realized I'm the dummy as far as that space goes... the leading space was causing some problems.  When I just use: !setattr {{ --sel --dummy|%npc_str_save_flag% }} I get the expected result of: Setting attributes Setting dummy to 0 for character Copy of Animal Testing. For some reason that space didn't seem to affect setting the proficiency bonus, so I assumed (very incorrectly) it was being parsed out in all cases.
1577825271

Edited 1577825483
I really wish I could understand a bit more of what's going on under the hood with these attribute fields and how they are set.  I'm just not seeing the logic in how things are failing with these commands. On a fresh test subject (never altered with ChatSetAttr), I tried: !setattr {{ --sel --evaluate --pb_custom|(%pb_custom% < @{Snow White|pb})?@{Snow White|pb}:%pb_custom% --intelligence|@{Snow White|intelligence} --wisdom|@{Snow White|wisdom} --charisma|@{Snow White|charisma} --npc_saving_flag|1 --npc_con_save_flag|1 --npc_con_save|0 --npc_wis_save_flag|1 --npc_wis_save|0 --npc_cha_save_flag|1 --npc_cha_save|0 }} Which seemed to work fine, giving me the expected results and no errors: 12:09PM (From ChatSetAttr): Setting attributes Setting pb_custom to 3, npc_cha_save_flag to 1, npc_cha_save to 0, npc_wis_save_flag to 1, npc_wis_save to 0, npc_con_save_flag to 1, npc_con_save to 0, npc_saving_flag to 1, intelligence to 11, wisdom to 14, charisma to 10 for character Copy of Animal Testing. I tried to verify that by running the chat command: @{selected|pb_custom} @{selected|npc_cha_save} @{selected|npc_con_save} @{selected|npc_wis_save} Which returned (as expected): 12:10PM KC . (GM): 3 0 0 0 But then when I tried this afterwards: !setattr {{ --sel --mod --npc_con_save|%pb_custom% --npc_con_save|%constitution_mod% --npc_wis_save|%pb_custom% --npc_wis_save|%wisdom_mod% --npc_cha_save|%pb_custom% --npc_cha_save|%charisma_mod% }} I got these results: 12:11PM (From ChatSetAttr): Errors Attribute npc_cha_save is not number-valued for character Copy of Animal Testing. Attribute left unchanged. Attribute npc_con_save is not number-valued for character Copy of Animal Testing. Attribute left unchanged. 12:11PM (From ChatSetAttr): Setting attributes Setting npc_wis_save to 2 for character Copy of Animal Testing. Why would it half-work for npc_wis_save (adding the wisdom_mod, but not the pb_custom) and not work at all for the others?  Why would that attribute be considered number-valued while the others don't, even though they were all assigned the value of 0 in the same way? Doing a little more trouble-shooting, it seems like the error message might be a little off, because when I tried: !setattr {{ --sel --mod --npc_con_save|%constitution_mod% }} I got the error: 12:27PM (From ChatSetAttr): Errors Attribute npc_con_save is not number-valued for character Copy of Animal Testing. Attribute left unchanged. 12:27PM (From ChatSetAttr): Setting attributes Nothing to do for character Copy of Animal Testing. But when I added a number instead of an attribute that I thought would be considered a number: !setattr {{ --sel --mod --npc_con_save|1 }} It worked as expected: 12:28PM (From ChatSetAttr): Setting attributes Setting npc_con_save to 1 for character Copy of Animal Testing. So it seems that the attribute being modified was number-valued, but the value being added to it was not, which makes some sense given the command used and would explain at least why the pb_custom wasn't added in the mod operation (since it wasn't set by an explicit number in the first operation), but it still doesn't explain why the earlier mod operation didn't fail completely for all attributes. At this point, I'm really not sure what else to try.
1577900021
Jakob
Pro
Sheet Author
API Scripter
Alright, so what the script does what it sees an expression like %constitution_mod% is that it will replace the whole thing with the value returned by  getAttrByName("constitution_mod") (or an empty string if it is undefined). getAttrByName is a built-in function that (as far as I understand it) should get the current value of the constitution_mod attribute of the character to be modified, if it exists; the default value of the given sheet for the constitution_mod attribute, if it exists; undefined otherwise. I'm not certain that getAttrByName works correctly in all situations; I can't really test this stuff anymore since my Roll20 subscription ran out and I'm not really willing to pay anymore for an API that the Roll20 team clearly doesn't care about, but that's beside the point here. So the fact is that whatever constitution_mod is evaluating to, it doesn't look like a number. I have no idea why; you can run something like !setattr --sel --dummy|%constitution_mod% to find out. I don't know why this is different from wisdom_mod or charisma_mod. You might be running into the fact here that sheet workers using event.newValue and event.previousValue (like in the 5E OGL sheet) have always been broken when being used from the API and that no one is fixing it (see the stickied thread in this subforum). Sorry for the misleading error message: it is indeed not the current value of the attribute, but the value being added to it in this case that fails to parse as a number. Addendum 1: The script syntax is a bit limited. Specifying the same attribute twice like this: --npc_con_save|%pb_custom% --npc_con_save|%constitution_mod% is not supposed to add both things to npc_con_save; at best, it will ignore the first directive and just set npc_con_save to whatever %constitution_mod% evaluates to.
1577902494

Edited 1577902509
Thanks for the reply, Jakob, especially given that it sounds like you've already given up on these things.  I really appreciate the explanation and of course all the effort you've put in to the API scripts you made.  I'm sorry about the source of your frustrations. I already imagined the problems I'm having are at least partially rooted in the construction of the 5E OGL sheet and I figured the rest were in my ignorance of syntax and the processes behind ChatSetAttr. Your addendum explains that I would need to at least add another macro step to do what I want (one to add pb_custom, then another to add ability modifiers), so that's very helpful information to have. As you suggested though, %constitution_mod% isn't evaluating as expected.  Looking at the attribute field for constitution_mod, I see a 0 displayed, but trying: !set_attr --sel dummy|%constitution_mod% Results in: Setting attributes Setting dummy to (empty) for character Copy of Animal Testing. The same holds true for a few other attributes I've tested that display a 0, but not for all of them.  For instance: !setattr --sel --dummy|%spell_save_dc% Results in: Setting attributes Setting dummy to 0 for character Copy of Animal Testing. Those kinds of inconsistencies are especially frustrating, but you've given me yet another tool for testing the sheet and finding those things so perhaps after evaluating all the existing attribute fields I might have enough information to be able to hammer out some kind of solution.
1577907554
Jakob
Pro
Sheet Author
API Scripter
Oh! So the most likely case here is that getAttrByName is not returning the correct default value for this field, so it's trying to interpret the empty string as a number, and failing (" (empty) " means an empty string for the field value. Unfortunately, the API has no access to the default values in the sheet's HTML, so if getAttrByName doesn't return the right thing, there's no way of knowing that constitution_mod should be 0 instead (as you have discovered, the @{foo} chat syntax works differently). One workaround would be to explicitly set it to 0 before at least once on this character (since it's the default value, that shouldn't change a thing). I assume that it would correctly from then on. You could even automate this !setattr --all --evaluate --constitution_mod|"%constitution_mod%" ? "%constitution_mod%" : "0" Sorry for the trouble! There's a lot of strange limitations to deal with in API scripts, mostly due to lack of information or outdated interfaces ;).
Many thanks!  It's working as expected now!  I had one lingering error that turned out to be an errant zero on the player character's sheet, but that's all fixed. I now have a set of three macros that when run sequentially will go pretty far in correctly setting up Wild Shapes for a Druid: giving the beast the Druid's mental stats, proficiency bonus (if higher) used to recalculate the beast's existing skills/saves, and adding the Druid's skills/saves to be calculated with the beast's new stats.  There's lots of stuff not covered that could potentially be added to Wild Shapes (like Jack of All Trades, Expertise, other class features/feats, etc.) but I'm very happy to have the base stuff covered for skill checks and saving throws at least.  The first macro changes the proficiency bonus and mental stats: !setattr {{ --sel --evaluate --pb_custom|(%pb_custom% < @{Snow White|pb}) ? @{Snow White|pb} : %pb_custom% --intelligence|@{Snow White|intelligence} --intelligence_mod|@{Snow White|intelligence_mod} --wisdom|@{Snow White|wisdom} --wisdom_mod|@{Snow White|wisdom_mod} --charisma|@{Snow White|charisma} --charisma_mod|@{Snow White|charisma_mod} }} The second one makes sure that all the necessary fields are actually using numbers for the attributes to be evaluated: !setattr {{ --sel --evaluate --strength_mod|"%strength_mod%" ? "%strength_mod%" : "0" --dexterity_mod|"%dexterity_mod%" ? "%dexterity_mod%" : "0" --constitution_mod|"%constitution_mod%" ? "%constitution_mod%" : "0" --intelligence_mod|"%intelligence_mod%" ? "%intelligence_mod%" : "0" --wisdom_mod|"%wisdom_mod%" ? "%wisdom_mod%" : "0" --charisma_mod|"%charisma_mod%" ? "%charisma_mod%" : "0" --npc_str_save_flag|"%npc_str_save_flag%" ? "%npc_str_save_flag%" : "0" --npc_dex_save_flag|"%npc_dex_save_flag%" ? "%npc_dex_save_flag%" : "0" --npc_con_save_flag|"%npc_con_save_flag%" ? "%npc_con_save_flag%" : "0" --npc_int_save_flag|"%npc_int_save_flag%" ? "%npc_int_save_flag%" : "0" --npc_wis_save_flag|"%npc_wis_save_flag%" ? "%npc_wis_save_flag%" : "0" --npc_cha_save_flag|"%npc_cha_save_flag%" ? "%npc_cha_save_flag%" : "0" --npc_athletics_flag|"%npc_athletics_flag%" ? "%npc_athletics_flag%" : "0" --npc_acrobatics_flag|"%npc_acrobatics_flag%" ? "%npc_acrobatics_flag%" : "0" --npc_sleight_of_hand_flag|"%npc_sleight_of_hand_flag%" ? "%npc_sleight_of_hand_flag%" : "0" --npc_stealth_flag|"%npc_stealth_flag%" ? "%npc_stealth_flag%" : "0" --npc_arcana_flag|"%npc_arcana_flag%" ? "%npc_arcana_flag%" : "0" --npc_history_flag|"%npc_history_flag%" ? "%npc_history_flag%" : "0" --npc_investigation_flag|"%npc_investigation_flag%" ? "%npc_investigation_flag%" : "0" --npc_nature_flag|"%npc_nature_flag%" ? "%npc_nature_flag%" : "0" --npc_religion_flag|"%npc_religion_flag%" ? "%npc_religion_flag%" : "0" --npc_animal_handling_flag|"%npc_animal_handling_flag%" ? "%npc_animal_handling_flag%" : "0" --npc_insight_flag|"%npc_insight_flag%" ? "%npc_insight_flag%" : "0" --npc_medicine_flag|"%npc_medicine_flag%" ? "%npc_medicine_flag%" : "0" --npc_perception_flag|"%npc_perception_flag%" ? "%npc_perception_flag%" : "0" --npc_survival_flag|"%npc_survival_flag%" ? "%npc_survival_flag%" : "0" --npc_deception_flag|"%npc_deception_flag%" ? "%npc_deception_flag%" : "0" --npc_intimidation_flag|"%npc_intimidation_flag%" ? "%npc_intimidation_flag%" : "0" --npc_performance_flag|"%npc_performance_flag%" ? "%npc_performance_flag%" : "0" --npc_persuasion_flag|"%npc_persuasion_flag%" ? "%npc_persuasion_flag%" : "0" }} The final macro compares saves/skills between the Druid and the beast and adds the newly calculated values to the beast: !setattr {{ --sel --evaluate --npc_saving_flag|1 --npc_skills_flag|1 --npc_str_save_flag|(@{Snow White|strength_save_prof}!==0)?1:%npc_str_save_flag% --npc_dex_save_flag|(@{Snow White|dexterity_save_prof}!==0)?1:%npc_dex_save_flag% --npc_con_save_flag|(@{Snow White|constitution_save_prof}!==0)?1:%npc_con_save_flag% --npc_int_save_flag|(@{Snow White|intelligence_save_prof}!==0)?1:%npc_int_save_flag% --npc_wis_save_flag|(@{Snow White|wisdom_save_prof}!==0)?1:%npc_wis_save_flag% --npc_cha_save_flag|(@{Snow White|charisma_save_prof}!==0)?1:%npc_cha_save_flag% --npc_athletics_flag|(@{Snow White|athletics_prof}!==0)?1:%npc_athletics_flag% --npc_acrobatics_flag|(@{Snow White|acrobatics_prof}!==0)?1:%npc_acrobatics_flag% --npc_sleight_of_hand_flag|(@{Snow White|sleight_of_hand_prof}!==0)?1:%npc_sleight_of_hand_flag% --npc_stealth_flag|(@{Snow White|stealth_prof}!==0)?1:%npc_stealth_flag% --npc_arcana_flag|(@{Snow White|arcana_prof}!==0)?1:%npc_arcana_flag% --npc_history_flag|(@{Snow White|history_prof}!==0)?1:%npc_history_flag% --npc_investigation_flag|(@{Snow White|investigation_prof}!==0)?1:%npc_investigation_flag% --npc_nature_flag|(@{Snow White|nature_prof}!==0)?1:%npc_nature_flag% --npc_religion_flag|(@{Snow White|religion_prof}!==0)?1:%npc_religion_flag% --npc_animal_handling_flag|(@{Snow White|animal_handling_prof}!==0)?1:%npc_animal_handling_flag% --npc_insight_flag|(@{Snow White|insight_prof}!==0)?1:%npc_insight_flag% --npc_medicine_flag|(@{Snow White|medicine_prof}!==0)?1:%npc_medicine_flag% --npc_perception_flag|(@{Snow White|perception_prof}!==0)?1:%npc_perception_flag% --npc_survival_flag|(@{Snow White|survival_prof}!==0)?1:%npc_survival_flag% --npc_deception_flag|(@{Snow White|deception_prof}!==0)?1:%npc_deception_flag% --npc_intimidation_flag|(@{Snow White|intimidation_prof}!==0)?1:%npc_intimidation_flag% --npc_performance_flag|(@{Snow White|performance_prof}!==0)?1:%npc_performance_flag% --npc_persuasion_flag|(@{Snow White|persuasion_prof}!==0)?1:%npc_persuasion_flag% --npc_str_save|(%pb_custom% + %strength_mod%) --npc_dex_save|(%pb_custom% + %dexterity_mod%) --npc_con_save|(%pb_custom% + %constitution_mod%) --npc_int_save|(%pb_custom% + %intelligence_mod%) --npc_wis_save|(%pb_custom% + %wisdom_mod%) --npc_cha_save|(%pb_custom% + %charisma_mod%) --npc_athletics|(%pb_custom% + %strength_mod%) --npc_acrobatics|(%pb_custom% + %dexterity_mod%) --npc_sleight_of_hand|(%pb_custom% + %dexterity_mod%) --npc_stealth|(%pb_custom% + %dexterity_mod%) --npc_arcana|(%pb_custom% + %intelligence_mod%) --npc_history|(%pb_custom% + %intelligence_mod%) --npc_investigation|(%pb_custom% + %intelligence_mod%) --npc_nature|(%pb_custom% + %intelligence_mod%) --npc_religion|(%pb_custom% + %intelligence_mod%) --npc_animal_handling|(%pb_custom% + %wisdom_mod%) --npc_insight|(%pb_custom% + %wisdom_mod%) --npc_medicine|(%pb_custom% + %wisdom_mod%) --npc_perception|(%pb_custom% + %wisdom_mod%) --npc_survival|(%pb_custom% + %wisdom_mod%) --npc_cha_save|(%pb_custom% + %charisma_mod%) --npc_cha_save|(%pb_custom% + %charisma_mod%) --npc_cha_save|(%pb_custom% + %charisma_mod%) --npc_cha_save|(%pb_custom% + %charisma_mod%) }} I quickly tried a version using @{target|attribute} syntax instead of {@Snow White|attribute}, because that would be a little more ideal than having to replace the name for each individual Druid who needs these.  I found this explanation that The Aaron wrote concerning TokenMod, but I haven't yet tested if ChatSetAttr uses the same workaround syntax: There is a bug with Roll20 where if you are using the @{target} specifier to get some information, you have to specify the --ids explicitly as the msg.selected will be empty.  If you've got more than one token you're changing, something like this would work: !token-mod --set imgsrc|+@{target|source|token_id} --ids @{target|dest1|token_id} @{target|dest2|token_id} @{target|dest3|token_id} @{target|dest4|token_id} @{target|dest5|token_id} @{target|dest6|token_id} You can just click the same destination token several times if you have fewer than 6. Regardless, I'm extremely happy to have this functioning fully after a few frustrating days!  Thanks again, Jakob!
1577967753
Jakob
Pro
Sheet Author
API Scripter
Glad that it works now! I think that you should be able to use multiple targets to make this work: use --charid @{target|first_target|character_id} to select the character to apply adjustments to, and @{target|second_target|foo} to select the character as the source for attribute value foo.