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

[Help] I am creating my second script, but have hit a wall.

1572447213
Layton
API Scripter
What I am trying to do overall is to create a perfect Wild-Shape script for 5th Edition D&D using the Roll20 5e OGL Sheet and pre-allocated beasts which are set up in the journal. The part I am stuck on is the system of changing or replacing the characters token and sheet with that of a selected beast. My original intention was to: Duplicate the beast's sheet, append the character's name to the start, & remove ' (COPY)' from the end. Place that copy's default token at the coords of the player's token. Remove the player's token from the board. Give the player control of the new sheet (and therefore the new token). Make the appropriate adjustments to ability bonuses. When a different command is triggered, delete the copy sheet & token, and re-place the character's token. I believe I have done everything around this process that would support it. However, I don't feel I have the knowledge to continue. Placing a character sheet's default token does not seem to be possible. Were it possible I feel I could continue un-assisted, which is my goal as I'm using the Roll20 API as a way to hone my knowledge of programming and advance in college. If there is some obvious solution I don't know about, or if there is a complex work around, I'd appreicate the knowledge. Thanks in advance for all help provided. - Layton
1572448536
The Aaron
Roll20 Production Team
API Scripter
To create a character's default token, you: get the defaulttoken attribute from the character decode it to an object with JSON.parse() add the page id, layer, left, and top attributes to the object pass it to createObj('graphic', HERE) to make the graphic.  In your case, there's a 3b you need to do. Since you're duplicating a character, your new character will have the source character's defaulttoken. That means you need to update the represents property to point to the new character.  Additionally, the API can only create graphics that are in a User Library. If your token's image came from a compendium, marketplace set, module, or addon, you'll need to download it a d upload it to a user library or the createObj will make an empty graphic. 
1572448923
Layton
API Scripter
Thanks very much! Could I ask what a 3b is? Other than that I think this was absolutely all the information I needed.
1572449262

Edited 1572449330
Davemania
KS Backer
Sheet Author
API Scripter
This certainly sounds like a heroic effort, and I hope you get it working the way you like! The only insight I can offer is that a possible work around may be to create a brand new token on the board that mimics everything about the default token associated with the sheet. The only janky bit might be having to define the imgsrc and the height/width of the token explicitly based on what you're wildshaping into. e: The Aaron certainly knows better than I!
1572450431
Layton
API Scripter
I'm running some test code and getting an error that I can't locate. I'm sure its something tiny, but nothing that I can identify. SyntaxError: Unexpected token u in JSON at position 0 on ( 'ready' ,  function (){      log ( 'test ready' );      let   beast   =   findObjs ({          _type :  'character' ,           name :  `allora ti'el`     }, { caseInsensitive :  true })[ 0 ];      let   tokenBlob   =   JSON . parse ( beast . get ( '_defaulttoken' ));      log ( tokenBlob );      let   campaignObj   =   getObj ( 'campaign' ,  'root' );      let   pageID   =  campaignObj . get ( 'playerpageid' );     tokenBlob . set ({          _pageid :  pageID ,          left :  400 ,          top :  400 ,          represents :  'Brown Bear' ,          name :  'Allora the New'     });      let   createdToken   =   createObj ( 'graphic' ,  tokenBlob );      log ( 'Test finished.   ' + createdToken . get ( 'name' ) + ' created, representing   ' + createdToken . get ( 'represents' ) + '.' ); });
1572451565
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Layton said: Thanks very much! Could I ask what a 3b is? Other than that I think this was absolutely all the information I needed. I presume 3b = That means you need to update the represents property to point to the new character.
1572455467
The Aaron
Roll20 Production Team
API Scripter
3b as in "second half of step 3)". Like step 3.5, thing to do before step 4) and after step 3). Sorry I wasn't more clear! =D That error means the contents of defaulttoken is not valid JSON. Probably it's returning "undefined", which is why character 0 (zero biased array) is 'u'.  Try logging the output of that get. 
1572513321

Edited 1572519873
Layton
API Scripter
EDIT: Worked this part out unassisted. Thanks for the help thusfar, I've made some progress. I'm now stuck, however, on a weird... thing. I'm getting this error, and I don't know why: TypeError: obj.set is not a function on ( 'ready' ,  function (){      log ( 'test ready' );      let   beast   =   findObjs ({          _type :  'character' ,           name :  `allora ti'el`     }, { caseInsensitive :  true })[ 0 ];      log ( 'beast:   ' + beast );  // [object Object]      let   campaign   =   getObj ( 'campaign' ,  'root' );      let   playerPage   =  campaign . get ( 'playerpageid' );     beast . get ( '_defaulttoken' ,  function ( o ) {          log ( 'o:   ' + o );  // long string                   let   obj   =   JSON . parse ( o );          log ( 'obj:   ' + obj )  // [object Object]         obj . set ({              _pageid :  playerPage ,              layer :  'objects' ,              left :  300 ,              top :  200         })          createObj ( 'graphic' ,  obj );     }); }); I understand what the error means, but not how I would remedy it. Again, all help appreciated. Thanks.
1572518678
GiGs
Pro
Sheet Author
API Scripter
You seem to be missing a step or two from your original plan. Your first goal was to make a copy of the bear sheet, and then manipulate in various ways.  Here's a quick script that will copy an existing sheet named Brown Bear, use the original character's name and add the bears name in brackets. From there you should be able to change the represents, control, etc. on('ready', function(){ on("chat:message", function(msg) { if(msg.type == "api" && msg.content.startsWith("!shape") !== -1) { let beast = findObjs({ _type: 'character', name: `Brown Bear` }, {caseInsensitive: true})[0]; let newshape = createObj("character", JSON.parse(JSON.stringify(beast))); newshape.set({name: `Allora the New (${newshape.get('name')})`}) } }); });
1572520054
Layton
API Scripter
GiGs said: You seem to be missing a step or two from your original plan. Yes, I did not include my entire script, only the part I needed help with. The rest of the script (such as the part you have sent me) I already have prepared since my original post. Thanks regardless though, as you've written the name setting in a more intuitive way.
1572834675
The Aaron
Roll20 Production Team
API Scripter
There are two types of objects you're dealing with. This creates a Javascript object, which is just a simple key/value structure: let   obj   =   JSON . parse ( o ); That means if you want to set a property like top, you just do it directly: obj.top = 300; What you get from Roll20 functions (createObj, getObj, findObjs, first argument of event handlers, etc) is a Roll20 object. Roll20 objects are basically a proxy to storage somewhere else, and have a function interface using .set(), .get(), etc.  You need to use the right interface for each object. It will becomes second nature eventually. 
1572850853
GiGs
Pro
Sheet Author
API Scripter
The Aaron said: You need to use the right interface for each object. It will becomes second nature eventually.  I'm still waiting for that day myself ;)
1572864237
Layton
API Scripter
Script is done! Just going through bug testing and extra features before I post it. Thanks for the help!
1572869999
The Aaron
Roll20 Production Team
API Scripter
Woot! Good job!!
1572949290

Edited 1572949346
Layton
API Scripter
Sorry to revive a dead thread, but is there an easier way of doing this? It seems like I should be able to do this in some short-hand manner.
1572950760
GiGs
Pro
Sheet Author
API Scripter
First, when posting code snippets, please post them as text, not a screenshot. It's much easier to copy and edit them to reply that way. You can do this: obj[`bar${AWS_hpbar}_value`] = getAttrByName(char.id,'hp'); You might want to check that AWS_hpbar is a valid value between 1-3 first though. Depending on the rest of your code, this might not be needed of course.
1572976404
Layton
API Scripter
GiGs said: First, when posting code snippets, please post them as text, not a screenshot. Sorry about that! Will do as you suggest in future. GiGs said: You can do this: obj[`bar${AWS_hpbar}_value`] = getAttrByName(char.id,'hp'); That's exactly what I was after, thanks so much! Does this technique have a name? I was searching and searching online, but couldn't find it anywhere.
1572977135
GiGs
Pro
Sheet Author
API Scripter
I imagine it does have a name, but I dont know what it is. It's a combination of two techniques: string literals (the but inside the [ ]), and just standard javascript object assignments. With object variables, you have two ways to address a key:  obj.key_name and obj['key_name'] The second one is specifically for cases like this, where you dont know exactly what the key will be till runtime, so you need to be able to dynamically create a string, and use that to assign it.