[Script] ChatSetAttr - set character attributes via chat messages

1478064502

Edited 1478066148
Vince
Pro
Sheet Author
I have some old PF characters with repeating attacks with single digit repeating rowID's like 0,1,2, etc. It doesn't seem to be an issue except when I tried using ChatSetAttr to change some of the repeating attribute data it errors out saying the row doesn't exist on any of these old id's. I can run the same script on a newly created repeating attacks and it has no problem. I can even pull each of the old rows attribute data to chat without problem as well. Not sure why they don't get along with ChatSetAttr.  I have tried "$0" for the row as well as just "0" as the rowID(this crashes the script with "TypeError: Cannot read property '0' of null")  Perhaps it's the way the script evaluates rowID? Thoughts?   Thanks example of successfully pulling the name of the repeating row $0 to chat example of trying to delete name with ChatSetAttr;
1478080265
Jakob
Pro
Sheet Author
API Scripter
Ha, I was wondering when someone would manage to break my repeating section code :) ! Since the API has no means of accessing the row index, I had to recreate this inside the script, and simply didn't think of old-style repeating rowIDs (I expected my IDs to start with a dash). Should be fixed in the newest version now (it should now work with both 0 and $0). Tell me if it's not.
1478095562
Vince
Pro
Sheet Author
I'm an expert at finding the "edge" cases.  ;-) I'll report back later.  Thanks Jakob.
1478096307
Vince
Pro
Sheet Author
v1.0.2  Still getting  TypeError: Cannot read property '0' of null when using !delattr --sel --repeating_weapon_0_name   or   !delattr --sel --repeating_weapon_$0_name
1478096873
Jakob
Pro
Sheet Author
API Scripter
Vince said: v1.0.2  Still getting  TypeError: Cannot read property '0' of null when using !delattr --sel --repeating_weapon_0_name   or   !delattr --sel --repeating_weapon_$0_name Can you test it with the newest Github version (1.1)? One-click is not totally up to date yet.
1478099646
Vince
Pro
Sheet Author
Duh.  At work on phone.  I'll test later and post back.  Thanks
1478106552
The Aaron
Pro
API Scripter
Vince said: I'm an expert at finding the "edge" cases.  ;-) I'll corraborate his claim! =D
1478129294
Vince
Pro
Sheet Author
Quick test with v1.1 Using plain old row numbers works (Yea!) !delattr --sel --repeating_weapon_$0_name However, using the rowId in this case doesn't seem to do anything. No errors given, just some confirmation text.  I've verified the rowID is " 0 " for this character. !delattr --sel --repeating_weapon_0_name I think row numbers alone will work for what I need, but I can be a test subject if you wish to pursue it further. Thanks Jakob
1478131176
Vince
Pro
Sheet Author
While I can modify most repeating attributes now, I'm having an issue with one, "repeating_weapon_$0_macro-text". !delattr --sel --repeating_weapon_$0_macro-text The command runs fine, no errors and I get the confirmation text.  However nothing actually happens.  I thought perhaps it was because it was a textarea attribute, but I was able to delete other textarea without issue.  I even tried with a new character that has a "normal" rowID and had the same result. Thoughts?
1478162673

Edited 1478162961
Jakob
Pro
Sheet Author
API Scripter
Thanks a lot for helping me debug this! Regarding the '0' not working, that's very weird because I tested a similar case and it seemed to work, but I will try to test this. I have a suspicion about the other error (the dash inside macro-text)... regular expressions are a pain to debug. EDIT: regarding the silent fails, it's intended that delete doesn't give you an error when it fails to find the attribute... you might get a more useful error message if you use !setattr.
1478171052

Edited 1478177643
Jakob
Pro
Sheet Author
API Scripter
Okay, got it. I accidentally broke handling of repeating sections by ids in the whole process, seems I did not in fact test the final version. repeating_weapon_0_name should work now (at least I created a character with an attribute like this, and it seemed to work). Macro-text is a different problem that I had to test with the PF sheet to understand what happens: when you do !delattr --sel --repeating_weapon_$0_macro-text it actually deletes the macro-text attribute (I checked via API that this actually happens). However, as soon as there's no macro-text attribute in that row anymore, the sheet's default is filled in for it. So it may look like nothing happens, when it fact it does. You can check with e.g. !setattr --sel --repeating_weapon_$0_macro-text|3 that it actually finds the right attribute. If what you want to achieve is to actually empty the macro-text box, you would do !setattr --sel --repeating_weapon_$0_macro-text| Okay, that last bit doesn't actually work, since it seems an empty attribute is treated like a nonexistent one when it comes to defaults. You could set it to a single space !setattr --sel --repeating_weapon_$0_macro-text|' ' EDIT: Aaaaand while I was at it, I made repeating attribute parsing case-insensitive. I saw that the PF sheet actually exposes the rowid, but in lowercase. So this should be useful.
1478182199

Edited 1478182527
Vince
Pro
Sheet Author
Awesome Jakob.  You are right about the auto-fill and that is actually what I would like to happen in my use case for macro-text.  I probably was expecting to see "something", but since I was looking at some macro-text I had already manually cleared/reset, I wasn't going to see anything happen while starring at it.  ;-)  I have a ton of "carry-over" macro-text attacks from one of my custom PF sheets.  I'll report back.  Cheers UPDATE : works great with both rowID as well as row number.  Awesome sauce.  Thank you!
1478341644
Jakob
Pro
Sheet Author
API Scripter
Update 1.1.1 : Made error messages more compressed. Feedback now tells you what the script actually did, not what it intended to do. Bugfixes.
Is there a way to utilize a rollable table result as the value to be set?  !setattr --sel --random| [[1t[random] ]]
1479032858

Edited 1479033400
Jakob
Pro
Sheet Author
API Scripter
Malkindred said: Is there a way to utilize a rollable table result as the value to be set?  !setattr --sel --random| [[1t[random] ]] Hmm, probably. I just copy & pasted a function from the Wiki, but the following could potentially work. Can you try this and see if it works? https://gist.github.com/joesinghaus/83dc0633b7605dfc7b9ea273b9123648 If this stuff works, I'll put it into the main script.
1479044397

Edited 1479044890
I'm testing it now.  Prior to the change, it would only work with numbers inside the table, now it appears it is returning the results of the table with text as well. It's not updating the sheet correctly, but that's likely bad syntax on my end. I'll let you know, and thank you!!! --Edit, I should have said only numbers inside the table --Edit. It works great! Thank you again. 
Does floor work with --evaluate?
1479049361

Edited 1479049479
Jakob
Pro
Sheet Author
API Scripter
Malkindred said: Does floor work with --evaluate? I don't really  understand how this stuff (stuff = Javascript eval()) works, but I suppose you can use the standard Javascript libraries with it, so you could try and use e.g. Math.floor().
That worked! 
1479051519
Jakob
Pro
Sheet Author
API Scripter
Malkindred said: That worked!  Nice. You can do all sorts of cool stuff with --evaluate including math functions and conditional logic, but I'm never quite sure if it actually works in a particular case.
1479381362
Toby
Pro
Question, is it possible to use a roll query command to set the value, I have tried several different ways, and none of them seem to work, they all give rather... odd errors and crash the sandbox. ----- I have just gotten my hands on this, handy little script.  I had been using some very basic attr changing script, that was quite limited.  Thank you for making this.  Regarding your most recent update and your questions. --evaluate :: I'd say dont restrict it to GM, or if you restrict it, give an option to override.  There are plenty of instances where this might be a very useful thing for players to have access to.  Especially if it is embeded into a GM created global macro that is called by players.  They wont have direct direct access to the code it self (unless they go hunting for it).  But they will be able to use it functionally.  If it was GM only, I'd imagine that option would vanish. -!resetattr :: please bring it back.  Seems like a handy thing to have access to.
1479385724
Jakob
Pro
Sheet Author
API Scripter
Thanks for the interest, I'll try to answer your questions one by one... Roll query: --attributename|?{What to set it to?} should work... I've tried very hard to make the sandbox not  crash even with bogus input. Can you give me an example of what you tried, and which commands are crashing the sandbox? In the most recent versions added a globalconfig option for allowing players to use --name and --charid without checking for permission. I can add the same thing for --evaluate, with a big fat warning sign. --attribute|%attribute_max% should give you the same functionality as !resetattr. Is there any functionality I haven't thought of that you can achieve via !resetattr, but not with this?
1479389120
Toby
Pro
Thanks, that worked.  As for the sandbox crashing, apparently, I hadn't fully deactivated my other attr modifiying script and they were not playing nice..  So it was the other one trying to execute the roll query while not understanding any of the arguments. As for the !resetattr, there is just something elegant about a simple, no argument command to clear everything. As for other functionality that you haven't thought of, well, you have a selection option for --all and --allgm (nonplayers) but but what about allpl (for all tokens assigned to players. In any case, this is an awesome script, you have made all my bard players, and shapeshifters very, very happy.  Combine your script with the new changes on the DEV server to allow Chat commands to be registered as onChange() events. Woo! Now I just need to find a way to change HP based on con for both normal and max and I'll be golden.  Please, keep it up.
1479390734

Edited 1479390773
Jakob
Pro
Sheet Author
API Scripter
Ah, it's reassuring it wasn't CSA that crashed. You're never quite bug-free, but reasonably normal input really shouldn't crash it anymore at this point :). I'll see what I can do about implementing !resetattr in a way that doesn't bloat all the code with extra options. My question was more about functionality with regards to !resetattr, but I can certainly add an --allplayers such an option if it would be useful (you meant for all characters assigned to players? Because CSA does not touch tokens :)). Your HP problem can probably be solved with --evaluate in some manner... I've also just pushed 1.1.4 . New features: You can now create a new repeating row with repeating_<prefix>_-CREATE_<attributename>|<value> (so just substitute -CREATE for the id). If you assign several attributes (e.g. name, attack bonus, damage,...) in the same section (so with the same prefix), they will of course all end up in the same new repeating row, as they should. New option to let players use --evaluate. Access it, like playersCanModify, via !setattr-config. New shortcut !modattr for !setattr --mod.
1479397969
Vince
Pro
Sheet Author
This is a VERY nice addition Jakob.  I'm thinking "item drops"... Thanks Jakob said: You can now create a new repeating row with repeating_<prefix>_-CREATE_<attributename>|<value> (so just substitute -CREATE for the id). If you assign several attributes (e.g. name, attack bonus, damage,...) in the same section (so with the same prefix), they will of course all end up in the same new repeating row, as they should.
1479398889
Toby
Pro
So, wait, you can use this to create dynamic attributes inside of repeating sections?  Or create entirely new repeating section entries?  I can see a number of uses for that...  Say.. a Hero Labs import for spells... Godly.
1479399166
Vince
Pro
Sheet Author
Toby said: So, wait, you can use this to create dynamic attributes inside of repeating sections?  Or create entirely new repeating section entries?  I can see a number of uses for that...  Say.. a Hero Labs import for spells... Godly. Godly indeed...
1479399735
Jakob
Pro
Sheet Author
API Scripter
Toby said: So, wait, you can use this to create dynamic attributes inside of repeating sections?  Or create entirely new repeating section entries?  I can see a number of uses for that...  Say.. a Hero Labs import for spells... Godly. You have been able to create attributes inside existing repeating sections for a while, but creating a new repeating section is only possible from this version(please test this ... I hope it works in all cases). I had to write a 'fake' repeating row id generator that should ensure that the new row always appears at the bottom of any existing rows. If not, or if you get strange broken repeating rows, there's something wrong, but it seemed to work for me in all cases. Of course, this is going to be much more useful once we have sheet worker support...
1479411527
Vince
Pro
Sheet Author
Jakob said: Of course, this is going to be much more useful once we have sheet worker support... That is the missing link.  Any word if the Devs(Riley) is working on this?
1479412071
The Aaron
Pro
API Scripter
Jakob said: I had to write a 'fake' repeating row id generator that should ensure that the new row always appears at the bottom of any existing rows. If you want, this is the actual implementation: var generateUUID = (function() {     "use strict";     var a = 0, b = [];     return function() {         var c = (new Date()).getTime() + 0, d = c === a;         a = c;         for (var e = new Array(8), f = 7; 0 <= f; f--) {             e[f] = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(c % 64);             c = Math.floor(c / 64);         }         c = e.join("");         if (d) {             for (f = 11; 0 <= f && 63 === b[f]; f--) {                 b[f] = 0;             }             b[f]++;         } else {             for (f = 0; 12 > f; f++) {                 b[f] = Math.floor(64 * Math.random());             }         }         for (f = 0; 12 > f; f++){             c += "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".charAt(b[f]);         }         return c;     }; }()), generateRowID = function () {     "use strict";     return generateUUID().replace(/_/g, "Z"); };
1479413138

Edited 1479413259
Jakob
Pro
Sheet Author
API Scripter
Thanks Aaron! Does this generate an id that's larger than existing ones? If so, I'd better use this version
1479414186
The Aaron
Pro
API Scripter
The ids are not guaranteed sortable.  That said, this should be no different than existing behavior with clicking the [+] for a repeating section on a character sheet.  The front part of the key is a hash of the current time, basically the current ms time in base64.  The second part is basically a random base64 number.  The only way the sorting would get broken is if two different keys happened to be precisely a ((power of 64) +/- 1)ms apart such that the Z digit in one lined up with the _ digit in another (which is then replaced with Z).  Then it would sort based on the random string. However, I think that's probably well within acceptable limits.  =D
1479414397

Edited 1479415033
Jakob
Pro
Sheet Author
API Scripter
The Aaron said: The ids are not guaranteed sortable.  That said, this should be no different than existing behavior with clicking the [+] for a repeating section on a character sheet.  The front part of the key is a hash of the current time, basically the current ms time in base64.  The second part is basically a random base64 number.  The only way the sorting would get broken is if two different keys happened to be precisely a ((power of 64) +/- 1)ms apart such that the Z digit in one lined up with the _ digit in another (which is then replaced with Z).  Then it would sort based on the random string. However, I think that's probably well within acceptable limits.  =D If it's good enough for roll20, it's good enough for me :D. EDIT: Changed the script to actually generate a row id. Although -A0000000..00 has a charm of its own...
1479420602
Jakob
Pro
Sheet Author
API Scripter
Vince said: Jakob said: Of course, this is going to be much more useful once we have sheet worker support... That is the missing link.  Any word if the Devs(Riley) is working on this? Watching the thread ... https://app.roll20.net/forum/post/4124691/api-dev-server-update-10-slash-17-sheet-worker-support
1479454000
Vince
Pro
Sheet Author
The new repeating addition works wonderfully.  Just thought I would share; Here's a macro for the PF sheet that creates a repeating weapon for a short sword (adjust it for any weapon). !setattr {{ --sel --replace --repeating_weapon_-CREATE_enhancement|0 --repeating_weapon_-CREATE_masterwork|0 --repeating_weapon_-CREATE_name|Short Sword --repeating_weapon_-CREATE_attack| --repeating_weapon_-CREATE_attack-type|`{attk~melee} --repeating_weapon_-CREATE_vs|ac --repeating_weapon_-CREATE_crit_target|20 --repeating_weapon_-CREATE_crit-multiplier|2 --repeating_weapon_-CREATE_crit_confirm|0 --repeating_weapon_-CREATE_damage-dice-num|1 --repeating_weapon_-CREATE_damage-die|6 --repeating_weapon_-CREATE_damage| --repeating_weapon_-CREATE_dmage_ability_mult|1 --repeating_weapon_-CREATE_damage-ability|`{STR~mod} --repeating_weapon_-CREATE_damage-ability-max| --repeating_weapon_-CREATE_type|PS --repeating_weapon_-CREATE_range|0 --repeating_weapon_-CREATE_ammo|0 --repeating_weapon_-CREATE_proficiency|0 }}
1479725278
Jakob
Pro
Sheet Author
API Scripter
Toby said: As for the !resetattr, there is just something elegant about a simple, no argument command to clear everything. Ok ok, !resetattr (or --reset, same effect) is back in the newest Github version :).
1480049953
Toby
Pro
I have noticed a bug? maybe.. When creating token actions the --sel property does not function properly. @{weapon-2-damagemacro} !bw #atkinfo !setattr --sel --mod --ammo-1|-1 (!bw is the blind whisper api script Aaron made for me and #atkinfo contains a rolltemplate that is hidden from the players to give me attack/defense information about the selected/targeted tokens.  I have tried running the !setattr without it and alone with no other commands and the same result occurs.) When executing it from the token action bar it returns the following error in the chat: Error No target characters. You need to supply one of --all, --allgm, --sel, --charid, or --name. While this can be gotten past by using --name TokenName, it is frustrating especially for creating mass change token actions like would be useful for inspire confidence/heroics etc. Is this an api limitation or something you are aware of?
1480062354

Edited 1480164230
Jakob
Pro
Sheet Author
API Scripter
Toby said: I have noticed a bug? maybe.. When creating token actions the --sel property does not function properly. @{weapon-2-damagemacro} !bw #atkinfo !setattr --sel --mod --ammo-1|-1 (!bw is the blind whisper api script Aaron made for me and #atkinfo contains a rolltemplate that is hidden from the players to give me attack/defense information about the selected/targeted tokens.  I have tried running the !setattr without it and alone with no other commands and the same result occurs.) When executing it from the token action bar it returns the following error in the chat: Error No target characters. You need to supply one of --all, --allgm, --sel, --charid, or --name. While this can be gotten past by using --name TokenName, it is frustrating especially for creating mass change token actions like would be useful for inspire confidence/heroics etc. Is this an api limitation or something you are aware of? I do not seem to be able to reproduce this at all. I mean, it wouldn't work when you're doing it from the character sheet and have no one selected, but from the token action bar it works just fine. I don't know what's happening here, but if you're sure the issue persists, send me an invite in a PM, make me GM and I'll see what I can do. EDIT: So we figured out the problem, it was @{target|...} statements, which happen to deselect selected tokens.
1481813361
Jakob
Pro
Sheet Author
API Scripter
1.1.5 --charid, --sel, and --name are now additive. If you use several all of them, it will affect the union of the characters. # has been removed from the replacers (this will be BREAKING  for some macros). You can now separate an attribute and its value by your choice of '#' or '|', instead of just '|'. If you want to use '#' or '|' inside attribute values, they need to be escaped with a preceding backslash. The script should now be safe for being called by  messages from other API scripts. It treats messages from the API as having GM permissions.
1481824784
Vince
Pro
Sheet Author
Jakob said: 1.1.5 --charid, --sel, and --name are now additive. If you use several all of them, it will affect the union of the characters. Thanks for the continued support for your script Jakob. I'm ignorant.  ELI5, can you give an example of how that would be useful.  TIA
1481829412
Jakob
Pro
Sheet Author
API Scripter
Vince said: Jakob said: 1.1.5 --charid, --sel, and --name are now additive. If you use several all of them, it will affect the union of the characters. Thanks for the continued support for your script Jakob. I'm ignorant.  ELI5, can you give an example of how that would be useful.  TIA Hmm, good question. While the other major things on the list are something I have a use for, this was mostly done for conceptual reasons because there was no good reason the options should be exclusive :D. I guess you could make a macro with --sel --name ?{name} to affect selected characters AND anyone you name in one macro. Maybe it's useful to someone, and if not, it doesn't hurt.
1482969899
Any update on when roll20 will update so that changes made by this script trigger the sheet? I was hoping we would get it for Christmas.  It will make an already useful script even better!
1483026944

Edited 1483026968
Jakob
Pro
Sheet Author
API Scripter
Gary W. said: Any update on when roll20 will update so that changes made by this script trigger the sheet? I was hoping we would get it for Christmas.  It will make an already useful script even better! See  Thread . When Riley pushes the version live, I have a version of ChatSetAttr lying around that can optionally use the new setWithWorker function (will work only as well as the backend, of course).
1484214267
Jakob
Pro
Sheet Author
API Scripter
Ah, so I found out by accident that the order of a repeating section IS accessible to the API via the _reporder_prefix attribute ... so if I find the time, I can actually fix the repeating_$j_ variant to do the expected thing after all.
1484229025
The Aaron
Pro
API Scripter
Jakob said: Ah, so I found out by accident that the order of a repeating section IS accessible to the API via the _reporder_prefix attribute ... so if I find the time, I can actually fix the repeating_$j_ variant to do the expected thing after all. oh??
1484229777

Edited 1484230197
Jakob
Pro
Sheet Author
API Scripter
The Aaron said: Jakob said: Ah, so I found out by accident that the order of a repeating section IS accessible to the API via the _reporder_prefix attribute ... so if I find the time, I can actually fix the repeating_$j_ variant to do the expected thing after all. oh?? It's odd, nobody seemed to know this when I asked this a while back, but when a repeating section has been reordered at least once, there is an attribute with name e.g. _reporder_repeating_attack associated to the character which stores a list of rowids separated by commas (in the order they are displayed in on the sheet). It gets out of sync when you add new rows, however, in the sense that newly-added rows are not added to the list unless you reorder something again. EDIT: ... and the same for deletion of rows. Overall, it's sufficient information to deduce the "order state" of the sheet, although it's again a bit annoying that you can't just pull it from the attribute. I haven't checked what exactly changing the attribute will do to the row order.
1484230179
The Aaron
Pro
API Scripter
Interesting.  I wonder if there is anything about that in old forum posts.
1484230521
The Aaron
Pro
API Scripter
Found it: https://app.roll20.net/forum/permalink/3051150/ Repeating Section Events and Attribute Sheetworkers can now listen for a change event of a special attribute that is modified whenever a repeating section is re-ordered. on("change:_reporder_repeating_<sectionname>"); You can also request the "_reporder_repeating_sectionname" attribute with getAttrs() to get a list of all the IDs in the section that have been ordered. However note that this may not include the full listing of all IDs in a section. Any IDs not in the list that are in the section are assumed to come after the ordered IDs in lexographic order. The API can also access this attribute using findObjs({_type: "attribute", name: "_reporder_repeating_<sectionname>"});
1484230640

Edited 1484230693
Jakob
Pro
Sheet Author
API Scripter
The Aaron said: Interesting.  I wonder if there is anything about that in old forum posts. Can't be too old, since reorderable repeating sections have only been around for so long. Also, it turns out you can actually reorder the rows by modifying the attribute (although visuals will update only after reopening the sheet). So an API script could go and order... something by ... some criterion (I'm sure there's a good use case here somewhere). And if you set the attribute to nonsense, it will just revert to the default order. EDIT: Nice! So it was there all along...
1484231183
The Aaron
Pro
API Scripter
Yeah, I'll see about adding that to the API Wiki at some point...