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

Read journal folder contents?

1487094388

Edited 1487094830
DXWarlock
Sheet Author
API Scripter
I dug around the API documentation, but either I am missing something, or trying to do something not implemented. I sort all my NPC/encounters into folders under the journal by mob levels and environment such as: -Encounters -Forest     -Level1     -Level2 -Plains    -Level1    -Level2 ....and so on.. Instead of having to make a bunch of rollable tables that I have to keep updated to mirror the creatures I have made, Trying to just read the creatures themselves. What I'm trying to do is read all the mobs names under one folder to create a random encounter script. Such as !randomEnc Forest Level1 I can read the folder list fine using _journalfolder , but picking a specfic folder and pulling out all the character objects under that folder seems to be impossible? (Or I'm just not savvy enough to do so).
1487102661

Edited 1487109753
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
It's a string, so you need to JSON.parse it.
1487124698

Edited 1487124814
Lithl
Pro
Sheet Author
API Scripter
function getFolderObjects(objs) { return _.map(objs, function(o) {         if (_.isString(o)) {             return getObj('handout', o) || getObj('character', o);         }         if (_.isArray(o.i)) {             o.i = getFolderObjects(o.i);             return o;         }     }); } function getObjectFromFolder(path, folderData, getFolder) {     if (path.indexOf('.') < 0) {         if (getFolder) {             return _.find(folderData, (o) => o.n && o.n.toLowerCase() === path.toLowerCase()).i;         }         return _.find(folderData, (o) => o.get && o.get('name').toLowerCase() === path.toLowerCase());     }     path = path.split('.');     var folder = path.shift();     path = path.join('.');     folderData = _.find(folderData, (o) => o.n && o.n.toLowerCase() === folder.toLowerCase());     return getObjectFromFolder(path, folderData.i); } // usage: var folderData = getFolderObjects(JSON.parse(Campaign().get('journalfolder'))); var goblin13 = getObjectFromFolder('encounters.forest.level2.goblin #13', folderData); var level2PlainsMonsters = getObjectFromFolder('encounters.plains.level2', folderData, true); var randomLevel2PlainsMonster = _.shuffle(level2PlainsMonsters).shift(); getObjectFromFolder assumes no folder, character, or handout names contain periods. The path parameter is case-insensitive.
1487127741

Edited 1487128887
DXWarlock
Sheet Author
API Scripter
@Scott: Thanks! That got me the right direction. I got it 'sort of working' parsing it out once you pointed it was JSON. But actually doing the logic to find by name was still kicking my kester.  @Brian: Man that is a pile of WAY more advanced JS than I know :) I'll give it a try picking that apart! Been trying to do it, on and off, for the last 4 hours. Between you and TheAaron you guy are the reason 3/4 of my scripts work LOL.
1487133044
Lithl
Pro
Sheet Author
API Scripter
function getFolderObjects(objs) { // _.map takes a collection and uses some function to transform each element into something else return _.map(objs, function(o) { // check if the current element of the collection is a string (an id for a character or handout)         if (_.isString(o)) { // return the handout, or the character if it's not a handout's id             return getObj('handout', o) || getObj('character', o);         } // if the element isn't a string, it should be an object; one of its properties should be i, which should be an array         if (_.isArray(o.i)) { // the i property is the contents of the folder, so recursively call this function to get the objects in the folder             o.i = getFolderObjects(o.i); // return the folder             return o;         }     }); } function getObjectFromFolder(path, folderData, getFolder) { // if path contains a period     if (path.indexOf('.') < 0) { // if the client code wants a folder returned         if (getFolder) { // _.find returns the first element in a collection that passes the predicate function // "(o) => ..." is shorthand for "function(o) { return ...; }" // a lambda function like this has some implications for the `this` keyword, but they're not relevant here // the function body will make sure the element has a name and the name matches the path             return _.find(folderData, (o) => o.n && o.n.toLowerCase() === path.toLowerCase()).i;         } // if this line is reached, the client code wants a character/handout // the function body will make sure the element has a get function and that the name matches the path         return _.find(folderData, (o) => o.get && o.get('name').toLowerCase() === path.toLowerCase());     } // if this line is reached, the path is trying to reach something inside a folder // split the path by the separator (period); "a.b.c" becomes ["a", "b", "c"]     path = path.split('.'); // the first part of the path is a folder // path.shift removes the first element from the array and returns the value // ["a", "b", "c"] becomes ["b", "c"] and folder becomes "a"     var folder = path.shift(); // turn path back into a period-separated list; ["b", "c"] becomes "b.c"     path = path.join('.'); // the function body finds the folder with the name of `folder`     folderData = _.find(folderData, (o) => o.n && o.n.toLowerCase() === folder.toLowerCase()); // recursively call this function to drill deeper into the folder structure     return getObjectFromFolder(path, folderData.i); } Do the comments help at all? =)
1487133610

Edited 1487133712
DXWarlock
Sheet Author
API Scripter
Yep! I got it working great after something trial and error. But the comments are a great help, now I can tell why it works vs how it 'just works'. :) Sometimes my coding procedure is " Find someone else's code, realize I dont know what some of it actually does, toss variations of the variables I think it needs at it until it stops throwing errors, and it returns what I expected (or at least close enough I can work with them) ." For example I saw that '(o) =>' was doing something to return what I needed for paths logging it, and it was working. Just not sure how it was, never used that before. Now I know.
1487172914
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
DXWarlock said: Sometimes my coding procedure is " Find someone else's code, realize I dont know what some of it actually does, toss variations of the variables I think it needs at it until it stops throwing errors, and it returns what I expected (or at least close enough I can work with them) ." For example I saw that '(o) =>' was doing something to return what I needed for paths logging it, and it was working. Just not sure how it was, never used that before. Now I know. I think this is a pretty common coding technique! Google is a great programming aid. :)
1487179557

Edited 1487179618
Lithl
Pro
Sheet Author
API Scripter
DXWarlock said: For example I saw that '(o) =>' was doing something to return what I needed for paths logging it, and it was working. Just not sure how it was, never used that before. Now I know. You can see a lot more information on arrow functions on the  Mozilla Developer Network . One of the most common 'gotchas' with them is how this  is handled differently from normal functions. Each time you call a normal function, a new value for this  is generated (unless you call bind() , call() , or apply() , in which case you get to assign the value for this ), although depending on the context in which it's happening it may simply be a reference to the global window  object. Not so for arrow functions. Compare: // non-strict mode, regular function call function example1() { console.log(this); // this === window setTimeout(function() { console.log(this); // this === window }, 1000); } example1(); // strict mode, regular function call function example2() { 'use strict'; console.log(this); // this === undefined setTimeout(function() { console.log(this); // this === window }, 1000); } example2(); // constructor call function example3() { this.foo = 'bar'; console.log(this); // this === { foo: 'bar' } setTimeout(function() { this.foo = 'baz'; console.log(this); // this === window }, 1000); } new example3(); // constructor call with closure on `this` function example4() { var self = this; self.foo = 'bar'; console.log(self); // self === this === { foo: 'bar' } setTimeout(function() { self.foo = 'baz'; console.log(self); // self === { foo: 'baz' } }, 1000); } new example4(); // strict mode, regular function call with arrow function function example5() { 'use strict'; console.log(this); // this === undefined setTimeout(() => console.log(this), 1000); // this === undefined } example5(); // constructor call with arrow function function example6() { this.foo = 'bar'; console.log(this); // this === { foo: 'bar' } setTimeout(() => { this.foo = 'baz'; console.log(this); // this === { foo: 'baz' } }, 1000); } new example6();