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 .
×
Create a free account

ChatSetAttr - Setting a resource to 0

1611735877

Edited 1611735988
Hello, I for the life of me cannot seem to figure out how to get ChatSetAttr to set a named resource to 0. To further complicate things, the resource exists on multiple characters sheets but won't be in the same physical location on each sheet due to other resources each character has.  Is there syntax for a macro I can run to set a resource to 0 by name for a selected token, without using the specific row ID? Closest I can come up with functionally is this, but it does not work. !setattr --sel --Intoxication Threshold|0
1611736266

Edited 1611736395
GiGs
Pro
Sheet Author
API Scripter
You need to identify the attribute name used on the character sheet for that resource. This is different from whatever is displayed visibly - its the name used in the underlying code. If its in a repeating section, they can be tricky to identify. A custom script could be built to find it wherever it is, but that's even trickier, and requires knowledge of how the sheet is structured.
1611736414

Edited 1611736493
Yeah, I’m aware of the row ID’s, and also the crazy string of numbers you can use for ammunition tracking, but the issue is that it’s impractical to have this resource in the same spot on everyone’s character sheet, so I can’t use a repeating row ID globally. 
1611737398
GiGs
Pro
Sheet Author
API Scripter
The row id would be unique per sheet anyway. It sound like there's no global oslution for your issue. You might be able to use the alternate row syntax (use $0, $1, etc in place of the row id) with chatSetAttrs (I can't remember if it supports it), but this would require that the resource is in the same position on each sheet. Since you can drag to move them, that might be the easiest solution.
1611742754

Edited 1612049558
Oosh
Sheet Author
API Scripter
EDIT - PasteBin link, code removed from below. Which sheet are you using? 5e, and the resources section(s)? GiGs' solution is by far the easiest, but if that's not possible you can search the sections with a script to find the resource. Of course, that means having a script dedicated to that one operation. Not a huge issue, unless you don't like bloating your script collection. edit - This script should work, anyway. It's pretty basic, only takes a few arguments, and is currently set up for 5e's resource sections (class, other and the repeating section). If you're using a different sheet you can add another object at the top following the same syntax as the "r20_5e" object, then change the 'currentSheet' variable to the new one and.... hopefully everything should still function. The few command arguments are: --char   can supply a name (exact match, not case sensitive), an ID, or sel (for selected token). Can use either --char|sel or just --sel for the selected token --name   the name of the resource you're trying to find (e.g. arrows, bolts). By itself, --name will just report the current/max values. --mod   what you want to do to the value. pretty basic so far +X, -X, or just X to set a straight value. + and - only work with numbers. Omitting the --mod operator will just report the target resource instead. --limit  supply a min or max separated by a comma. can write 'max' as the maximum to grab the max value of that resource. if you want to supply a max but no minimum, start with the comma, so --limit|,max --silent   disable chat whisper unless an error occurs. --silent will enable a once off flag, --silent|on and --silent|off will toggle the behaviour permanently --pub   publicly display resource set / display messages. Does not affect any other messages (like errors). Independent of - -silent , so for example " !findres --sel --name|arrows --silent --pub " will still silence the whisper, but post the current arrows for that character to public chat. example : !findres --char|sel --name|rage --mod|-1 --limit|0,max would search the whole resource section for a label "rage" and reduce it by one, unless it's already at 0. If it's accidentally been set over its maximum value previously, it would now be reduced to the maximum value. There's probably already something that does a similar job, but I was bored :) I didn't test it too heavily.
1611762386

Edited 1611762479
Hi Oosh! Wow, I’ll have to give that script a shot! I’m currently using the 5e OGL sheet, and that’s the ammunition tracking I’m using for resources as well, from the Companion script. Is there a difference between the 5e OGL and the r20_5e that I see the script using?  This is also for tracking a homebrew drinking rule’s intoxication threshold, which is why it can’t just put it in the same spot on every sheet, because not every character will drink, just a select few of them, hence my dilemma. 
1611763914

Edited 1611768188
Update: that script works exactly as intended! Thank you very much for the effort!  I do have a question for you if you're feeling generous Oosh, how easy would it be to make this have a silent output command like --silent inside of it which when registered would not output the script text into chat?
1611790444

Edited 1611790592
Oosh
Sheet Author
API Scripter
No problem, and yes the OGL sheet is the old name for the Roll20 5e sheet, so the section & attribute names are the same. On the silent thing - sure. Did you want all messages (like errors) suppressed as well? Or just successful changes, to save on spam? And would a message on hitting a set minimum or maximum be useful or just more spam?
I would like to still see errors, so I can tell if something is going wrong, but I would like to save on the chat spam.  As for the min/max message, it won't be necessary because the drinking homebrew I'm using this to help track intoxication with allows for exceeding the threshold, that's just when other things start to happen.  So if you have the time, a --silent function would be awesome!
1611805206

Edited 1611805278
Oosh
Sheet Author
API Scripter
No worries - added it in above.      --silent will enable a once off flag,      --silent|on and --silent|off will toggle the behaviour permanently. If you're finding any other chat feedback annoying, just search for it in the script and replace the "sendChat"  function name with "silentChat" and it will follow the silentMode setting, leaving any arguments & text in the brackets as they are. Let me know if anything goes wrong
Thanks, will do!
Update: I did run into an issue with setting the silent function permanently on, it gave me an error that shut down the API's I had installed. But, it runs fine with just using the --silent instead, so it's a non issue unless you want to troubleshoot it, but it works fine for my purposes. 
1611811044

Edited 1611811182
Oosh
Sheet Author
API Scripter
Whoops, I did have an error in there though it was related to not having a token selected. Fixed now. Do you have any idea what the error was? I can't get --silent to cause an error, hopefully you just ran into the 'no token selected' mistake I had in there. I also added a shortcut while I was there, you can use --sel instead of --char|sel After pasting into that quote box with a busted trackpad, I'm having regrets about not using pastebin...
From what I could tell, the error had occurred when at some point after I had used the "!findress --silent|on" function. I wasn't selected to a token at the time, so that may have been it.  
Oosh said: Whoops, I did have an error in there though it was related to not having a token selected. Fixed now. Do you have any idea what the error was? I can't get --silent to cause an error, hopefully you just ran into the 'no token selected' mistake I had in there. I also added a shortcut while I was there, you can use --sel instead of --char|sel After pasting into that quote box with a busted trackpad, I'm having regrets about not using pastebin... Like I said above, I do not know what the error was, but the script is currently working perfectly for me while just using --silent on the individual macros I’ve set up.  I do have one more thing that I’d be curious about the possibility of implementing, if you’re up to it.  Would it be possible to update the script with a --read command or similar to simply output the value already within a named resource? 
1612049894
Oosh
Sheet Author
API Scripter
No problem. Rather than adding another command, I just changed it so if you omit the --mod argument, it will report the current value instead. I also added a --pub flag to post values to public chat. This only affects two messages - the final "set" value if you modify a resource, or the display value if you use the new report-only functionality. It's also independent of --silent, so you can silence the whisper and send it to public chat, or neither, or both, or the other way around. It doesn't affect error messages or anything else. As with silent, you can switch it on and off permanently with --pub|on or --pub|off. Not sure if that's any use or not. Speaking of which, you should be use --silent|on ... I'm pretty sure the crash was the selected tokens bug (it was an ugly one) :)
Awesome! I will update the script in my campaign and let you know the results when I have time to test it!
Oosh I've finally had a chance to sit down and test and I think I miscommunicated my last request. In having the command without the --mod report the current value, I don't need that value sent to chat in a textbox, I would like to be able to call the macro nested in a query in order to insert that value into a calculation for a Difficulty check.  Currently, I have this set up by nesting a macro that runs "!findres --char|sel --name|Alcohol Tolerance" inside of my main macro, but it is not functioning as I would hope. Maybe I'm messing up the syntax, but I figured I'd ask ask if it was written to work that way first. 
1612305178

Edited 1612305298
Oosh
Sheet Author
API Scripter
Ah ok.... that's a bit more involved. I don't know if it's even possible in the way you're thinking of using it. You can send a value the other way - a chat-printed value can be grabbed by the script. But the message has already been sent to chat by the time the API starts running any code. So even if running the primary function of the script returned an integer (which it currently doesn't) it would be too late to do anything to the message you've nested it in. I think . Could probably use some guidance from one of the grown-up coders here. I could add a command that tells the script to spit out another chat message with the value inserted? I'm not sure what the best way to achieve that would be, I'll have a look at some other scripts. I'm thinking something like this: !findres --char|sel --name|Alcohol Tolerance --mod:+1 --macro|&{template:default} {{name=Use Value}} {{Tolerance=started at %value_intial%}} {{And then=ended at %value_final%/%value_max%}} The script runs as it does now, grabbing all the text following --macro, then runs a replacer right at the end with the options of %value_[initial / final / max]% being replaced by the calculated values. The result is then sent to chat. I don't really have any experience with mixing macro & API commands, this might be a silly way of doing it. One of the experienced folk might have a better suggestion before I start doing anything :) Could also throw an inline roll escape in there, like [$[ ]$], so you can send further calculations back to chat. For example, if the value affects a damage roll, you could run <blah blah blah> --macro|Damage Roll: [$[%value_final%d8]$] vomit damage and get Damage Roll: [[7d6]] vomit damage sent to chat (with the dice rolled).
@Oosh, a while back I was trying to find a way to adjust the Ammo script to look up a repeating entry by name, but I never got around to digging into it <a href="https://app.roll20.net/forum/permalink/9296300/" rel="nofollow">https://app.roll20.net/forum/permalink/9296300/</a> It looks like your script here can sort of do that. Is it pretty heavily geared toward interacting with the 5e sheet, or could it do something like in the example in the above link?
1612690487

Edited 1612690688
Oosh
Sheet Author
API Scripter
Yep, it could be used for that I think. It's currently set up for 5e but I left an Object &amp; variable right at the top to change that. It uses terms like "name" and "label" since it's searching the resources section for a particular name attribute, but really you can use it to search by any key or value . It would be much more useful if it was integrated into another script like CSA or Ammo, but my skills are too feeble to mess with the work of those authors, and they're both sheet-agnostic scripts... you'd need to make heavy use of some auto-configs and a good menu for setting up your searches before they'd function well for the community in general. But anyway, the top of the script looks like this: const r20_5e = { repSec: [ { sec: 'repeating_resource', nameAttrs: ['resource_left_name', 'resource_right_name'], // index of Name Attributes should match index of linked Value Attributes in next Array valAttrs: ['resource_left', 'resource_right'], } ], other: { nameAttrs: ['class_resource_name', 'other_resource_name'], // index of Name Attributes should match index of linked Value Attributes in next Array valAttrs: ['class_resource', 'other_resource'] } }; const currentSheet = r20_5e; You can copy the r20_5e object and paste underneath, rename it and change it to what you need. Then you just need to change the currentSheet variable to the name of the object you've created. The sheet settings object consists of two keys - one for the repeating sections you want to search, and one for the normal attributes you want to search. The repeating section part, repSec , is an array of objects - one object per repeating section you want to process (there's only one for the current 5e setting... but if you changed this to (for example) search for a spell name, and return the associated School, it would need 10 entries in here). The section name goes in sec . The Attributes you want to search for your string go in nameAttrs , and the Attributes you want the value returned from go in valAttrs . As the commenting says, these need to match indices: if your search term is found in (using the 5e settings above) resource_left_name at index 0 in the settings array, it's going to return the value of the Attribute at index 0 in the valAttrs array. It doesn't try to do any clever string matching of Attributes - I figured it was too risky considering how similar the attribute names in a repeating row can be. The 'other' section is the same, but has no sec key since it's for normal Attributes. It's also not an array, since normal attributes aren't split up into section names. And again, the indexing for the search Attribute and value-return Attribute need to match. I did integrate this into a ChatSetAttr-type function in another project, and used the syntax --?Rage?|?Rage_max? to let the attribute-setter know to call on the resources search, and sub in the actual repeating attribute before parsing the math and setting the value. It worked pretty well, but it was for a specific use, I didn't have to worry about the sheet-dependent nature of the script..
1612709758
timmaugh
Pro
API Scripter
I can add something to APILogic to help with this. It already has the ability to differentiate a repeating element based on pattern matching ("in THIS list, find the entry where THIS field is "arrows"), and it can already intercept the message to perform that differentiation before the "housing" command line would run. Right now, it can only return a sub-field OF that repeating element ("in THIS list, find the entry where THIS field is "arrows", and give me the field that ends in "count"). If I let you, instead return the attribute name (i.e., "repeating_resource_-M1234567890abcd_count"), then&nbsp; setattr &nbsp;will work just fine. It will give you real-time differentiation of a repeating attribute's sheet name by identifying enough data about the row. Let me see what I can cook up. (Also, next-phase dev on APIL is to include an "evaluate" tag that would give chat-level interaction to use a macro like Oosh's as a way to plug in scriplets to the interaction... meaning APILogic wouldn't launch another script, per se... but if someone wanted to write a scriplet to return a *value* you could return that to the command line in the position of the evaluate tag. It's like taking the game-data interaction and command line access of InsertArg, but marrying it with the timing magic and embed-ability of APIL.)
1612736517

Edited 1612759513
Thank you Oosh for the clear explanation! Okay so here's what I've tried changing it to for the Pathfinder Second Edition sheet (let me know if you catch any syntax errors!): const r20_PF2e = { repSec: [ { sec: 'repeating_items-readied', nameAttrs: ['readied_item'], // index of Name Attributes should match index of linked Value Attributes in next Array valAttrs: ['readied_quantity', 'readied_hit_points'], }, { sec: 'repeating_items-worn', nameAttrs: ['worn_item'], valAttrs: ['worn_quantity', 'worn_hit_points'], }, { sec: 'repeating_items-other', nameAttrs: ['other_item'], valAttrs: ['other_quantity', 'other_hit_points'], }, { sec: 'repeating_spellinnate', nameAttrs: ['name'], valAttrs: ['current_level', 'uses', 'uses_max'], }, { sec: 'repeating_spellfocus', nameAttrs: ['name'], valAttrs: ['current_level'], }, { sec: 'repeating_cantrip', nameAttrs: ['name'], valAttrs: ['current_level', 'uses', 'uses_max'], }, { sec: 'repeating_normalspells', nameAttrs: ['name'], valAttrs: ['current_level', 'uses', 'uses_max'], } ], other: { nameAttrs: ['focus_points', 'cantrips_per_day', 'level_1_per_day', 'level_2_per_day', 'level_3_per_day', 'level_4_per_day', 'level_5_per_day', 'level_6_per_day', 'level_7_per_day', 'level_8_per_day', 'level_9_per_day', 'level_10_per_day'], // index of Name Attributes should match index of linked Value Attributes in next Array valAttrs: ['focus_points', 'cantrips_per_day', 'level_1_per_day', 'level_2_per_day', 'level_3_per_day', 'level_4_per_day', 'level_5_per_day', 'level_6_per_day', 'level_7_per_day', 'level_8_per_day', 'level_9_per_day', 'level_10_per_day'] } }; const currentSheet = r20_PF2e; Repeating sections are set up for all three inventory categories, with a given item's quantity or hit points adjustable. all four spell categories, with the spell's heightened level and prepared uses adjustable. QUESTION : uses_max is technically just the max value for the uses attribute ( uses|max ); should I just leave that out and use the --limit|,max argument to set that value? Is there a way to set uses and its max value at once (e.g. set a spell to have 3/3 uses prepared)? Non-repeating sections: focus points (a pool for focus spells) and all other spell slots. Is setting these as both nameAttrs and valAttrs redundant? Each one is just a number attribute, no name attached, so could I remove the whole nameAttrs array from this section?
1612738150
Oosh
Sheet Author
API Scripter
That sounds awesome - I've gotten used to using a shortcut script !direct &lt;stuff here&gt; which just runs a try{eval(&lt;stuff here&gt;)} , it makes testing an awful lot easier since you don't need to worry about handling input. It also opens up some possibilities with other people's scripts if you know the functions. No idea how you're going to make this work in a public-safe script, but I'm keen to find out :)
1612759733

Edited 1612760416
Persephone said: QUESTION : uses_max is technically just the max value for the uses attribute ( uses|max ); should I just leave that out and use the --limit|,max argument to set that value? Is there a way to set uses and its max value at once (e.g. set a spell to have 3/3 uses prepared)? Non-repeating sections: focus points (a pool for focus spells) and all other spell slots. Is setting these as both nameAttrs and valAttrs redundant? Each one is just a number attribute, no name attached, so could I remove the whole nameAttrs array from this section? Oops, --limit|,max doesn't do what I thought it did. So I guess I'm wondering if this can alter a max value, or can it only use the max to to limit how the main value gets altered? Also I've been testing the changes I made. I put&nbsp; this button in a spell to test out, but it subtracts the spell level by default, rather than the uses. [Spend Spell Slot](!findres --char|@{character_id} --name|@{name} --mod|-1 --limit|0,max) Is there a way to specify which value in that index I want to alter? I'd like spells to have one button for marking as cast, like above, and one for altering spell level when necessary, like [Set Spell Level](!findres --char|@{character_id} --name|@{name} --mod|&amp;quest;{Level|1})
1612800080

Edited 1612800233
timmaugh
Pro
API Scripter
OK, I got APILogic updated to help with the original question (identifying a named repeating element when it could exist in different places on different characters). I've added the ability for an APILogic DEFINITION tag to evaluate the sheet item and return the appropriate piece of data -- including the name of the repeating item's sub-attribute. So if you wanted to, within the repeating list "resources", identify the attribute for&nbsp; threshold&nbsp; &nbsp;where the&nbsp; resource_name &nbsp;of the resource was "Intoxication", you could drop this in your chatsetattr command line: {&amp; define ([intoxattr] *name|Character Name|resources|[resource_name="Intoxication"]|threshold ) } (Note that I'm assuming this repeating list is named "resources" and the elements have suffixes of "resource_name" and "threshold". You can use the XRay script to walk the character sheet to make sure what these parts should be.) EDIT: Also note that while APILogic *should* get the message before the housing script does, the Roll20 parsers get the message before APILogic. That means instead of replacing "Character Name" (above) with the specific character's name, you could replace it, instead, with an @{selected} reference that returned the character's name. The above will return the name of the threshold attribute you are looking for, and assign it to intoxattr , Use that term elsewhere in your command line, and APILogic will substitute the sheet name before it releases the command line to chatsetattr. More is discussed at this post in the APILogic thread, and obviously at the first post in that thread.
1612865962
Oosh
Sheet Author
API Scripter
Persephone said: Oops, --limit|,max doesn't do what I thought it did. So I guess I'm wondering if this can alter a max value, or can it only use the max to to limit how the main value gets altered? Also I've been testing the changes I made. I put&nbsp; this button in a spell to test out, but it subtracts the spell level by default, rather than the uses. [Spend Spell Slot](!findres --char|@{character_id} --name|@{name} --mod|-1 --limit|0,max) Is there a way to specify which value in that index I want to alter? I'd like spells to have one button for marking as cast, like above, and one for altering spell level when necessary, like [Set Spell Level](!findres --char|@{character_id} --name|@{name} --mod|&amp;quest;{Level|1}) Yeah, the script won't really do any of that, it was thrown together with the 5e resources section in mind, which is very simple - 1 attribute which holds the name, 1 attribute which holds the value. There's currently no way to link more than 2 attributes in the repeating row together. I can definitely retool it a little so it works the way you want it to, but it looks like APILogic + CSA can already do it anyway - that would also give you much greater flexibility since APILogic can also hand off to tokenMod or haircutAPI or nudeSkinsForDragons or whatever script you like. Still, if you want me to look at it let me know... it mostly just needs the input and one function redone to do what you're asking.
@timmaugh, thank you for sharing that new feature, it looks fantastic! @Oosh, I think you're right about APILogic, I'm gonna dig into that more, but thanks for all the help so far. I learned new things while testing out your script!