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

[Script] Complete Set of Sample Images to Make Your "Dungeon Ready" (Random Dungeon Generator and Dynamic Lighting for Walls and Doors with Editing UI)

1419410307

Edited 1419410446
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Andrew said: When i add a GM Feature, it only the "North" indicator. Select it. You can then use the 10 User Interface Token Actions. Side Chooser “Fast Right.” (For objects that are multi-sided.) Side Chooser “Right.” Side Chooser “Left.” Side Chooser “Fast Left.” Flip Horizontal. Flip Vertical. Rotate Left 90 degrees Rotate Right 90 degrees. Turn 180 degrees. Paste-Selected. (Creates a copy of the selected object.) And, as with any Roll20 multi-sided token, you can also use the native "right click" choose side feature.
1419433694
Gen Kitty
Forum Champion
So I said I would play around with this and now I am. I thought I'd provide feedback as I go through the steps for setup and as I play with the creator. (This pretty much is a realtime capturing of my thought processes as I go) Phase 1: Just playing around with the script itself Setup was as easy as promised, though perhaps the warnings that 'One or more avatars are missing from the [named] rollable table (sample avatars provided as a substitute.)' could be reworded? I had a brief startle, wondering if something had gone wrong already. I made a sample dungeon, and yeah, random dungeon is random. (As an aside, why do GMs even *work* with random dungeons? They're nothing anyone sane would build. *muttermumble*) Sidenote: Random-Dungeon macro does not ask me for a weight. Is it supposed to? Adding & moving features is easy. I am unclear on what precisely the 'fast right/right/left/fast left' macros do that flipping and rotating don't do, but I'm sure I'll figure it out with some more tinkering. (Or you could just tell me ^_-) The dynamic lighting button is worth the price of entry. This is the wow factor, for me. Phase 2: Converting the watermarked images to non-water-marked images, via script (the one PMd me) Copy&Paste script, it worked, yay. I go to place the first tile... and gah! None of my purchases have tags? Ok, if I search 'Everything', I can search by filename. No, wait, that isn't consistent. At least my purchases *seem* to be sorted in the same order as the script is asking for.... Frustration over, I work on lining everything up.... Seriously? I can't resize the purchased art window to something wide and short? Why won't these images go where I *put* them, they've got to consistently jump one step to the right? This isn't the time warp... I reach the Geo_B_0030- series which is a bunch of practically identical tiles and I skip those for now, get everything else lined up, and I pause here because I've run out of time for the day x.x I'll finish this up later. My thoughts right now are "For all that is good and right, *why* aren't purchases tagged with their filenames as a starting tag? I'd have been done already if that was the case"
1419436136

Edited 1419436591
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Image management is challenging. If API could leverage tags and/or link to the Market items... this would be a breeze... however we don't have that yet, so its a bit clunky. 'fast right/right/left/fast left is a "Side Chooser" for the images (all the images are multi sided.) <a href="http://i.imgur.com/li6ZMAE.gif" rel="nofollow">http://i.imgur.com/li6ZMAE.gif</a> And setting up takes time.... There are a lot of images in this pack.... 150 or so. As to random maps, I mainly use it to just populate the map.... and then use the side chooser, flip and rotate to get the map to where I am happy with it. In the rollable table you can turn the weight to -1; which turns the tile off for random placement.
1419925374
vÍnce
Pro
Sheet Author
Ok, I've taken the plunge(more like a long walk off a short pier). Thank you Stephen. First off, this is a very nifty bit of trickery. Lot's of fun will be had with this in the future. I have things up and running on a separate campaign that will be used for Dungeon Ready map-making only. I haven't begun the process of swapping images yet. M u s t b u y m o r e c o f f e e... I've walked thru the intro instructions at the top of the thread without any issue except for when I try to use the [Light-Doors-Stairs] macro. On the map layer, I have some doors and a few torches(on) and I've already added dynamic lighting. But, when I try to run [Light-Doors-Stairs], I get an error in the api console; "TypeError: Cannot read property 'tileName' of undefined at evalmachine.&lt;anonymous&gt;:429:36 at Array.forEach (native) at Function._.each._.forEach (/home/symbly/www/d20-api-server/sandcastle/node_modules/underscore/underscore.js:78:11) at lightFeatures (evalmachine.&lt;anonymous&gt;:427:11) at handleInput (evalmachine.&lt;anonymous&gt;:364:29) at eval (" This is on the Dev server BTW, in case that matters. Suggestions?
1419937846
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Can you send me, in a PM, a copy of your script as it exist in your API. I think its a case sensitive issue in a string.
1419962601
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
I think I found the issue. At some point you copied and pasted a door or a torch..... that misses with the API (the new item will have a URL unknown to the API.) Delete those items (likely all of them).... and use the Token Action for copy and paste going forward,
1419970860

Edited 1419970914
vÍnce
Pro
Sheet Author
I see. I did use copy/paste on some doors. So, that's what the paste-selected macro is for...? Thanks Stephen. I'll see what I can break next.
1419971935
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Vince said: So, that's what the paste-selected macro is for...? Yeah and I just thought it would be easier when a GM is adding a bunch of torches or what not. I should be able to fix the the URLs from a copy and paste (its a issue with how API works) but that would be an update to the script.
1420312431
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
<a href="http://i.imgur.com/GxH5BQD.gifv" rel="nofollow">http://i.imgur.com/GxH5BQD.gifv</a> Working on caves.... minimal pathing overhead.
1420316387
vÍnce
Pro
Sheet Author
Very nice Stephen. I haven't messed with dungeonready much. Need to still do the image swap shuffle... I've been sucked into HB 's powercard v2.x and can't get out.
1420327093
The Aaron
Pro
API Scripter
That IS cool!
Vince said: Very nice Stephen. I haven't messed with dungeonready much. Need to still do the image swap shuffle... I've been sucked into HB 's powercard v2.x and can't get out. lol...
1420681973

Edited 1420683934
Any fix for the dynamic lighting on doors? I created a new campaign, did the set up, swapped out the graphics for the "storebought" ones and have made a few maps and played with features. It will help me a lot since I do a lot of on the fly dungeon making. The only thing I can find (I've not messed with the torches being on or off yet) that is not working according to the instructions are the dynamic lighting (thin green lines) on the doors. I can go on the DL layer and grab and move the thick blue lines for the walls, but cannot touch the ones for the doors. Update: on the next try, this time with torches of all things, the dl green lines for the doors work. Go figure. I should just mess around with it more before writing questions I see.
I purchased the packs months ago before this script was even made. I have to say, Stephen, this script is pretty simple to use that even an idiot such as myself can use. For that, I thank you. Is there any way to have a monster generator based on level that will auto populate character sheets that go hand in hand with the dungeon generator? I haven't looked at the packs in quite a while because of how daunting all of the tiles were, but, any way there can be a forest, swamp, etc, generator? Totally willing to donate, especially for a monster generator implemented in it.
Is that code for removing the sample tiles available? So far it's been super easy to get things working; it's just the watermarks that are driving me bananas.
1420927866

Edited 1420927891
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Purchase the “Dungeon Ready” pack here: Dungeon Ready And just replace the tiles in the Rollable table.... and or the URLs in the API with the URLs from your librays.
Already had 'em purchased and uploaded, just hoped there was a better process than updating each line. Bummer. Thanks, though.
1420938375
Gen Kitty
Forum Champion
There's a script, actually. I'm using it myself, sporadically, to convert my files. You'll need to either wait for Stephen to notice this thread, or PM him for the script.
1420945445
vÍnce
Pro
Sheet Author
Probably this one DungeonReadyImageSetup <a href="https://gist.github.com/BaldarSilveraxe/9ef2ae36180125da92b5" rel="nofollow">https://gist.github.com/BaldarSilveraxe/9ef2ae36180125da92b5</a> but I'm not sure how to use it.
1420970147
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Vince said: Probably this one DungeonReadyImageSetup <a href="https://gist.github.com/BaldarSilveraxe/9ef2ae36180125da92b5" rel="nofollow">https://gist.github.com/BaldarSilveraxe/9ef2ae36180125da92b5</a> but I'm not sure how to use it. Yeah. That is a try at it. There is really no good way to do it. The API does not have access to tags.
1422999522
vÍnce
Pro
Sheet Author
Couple questions. I replaced my images in the rollable tables swapping out from local copies on my computer. Any reason to upload them to my library other than to use the images outside of DR? Second question, what do you recommend for scale(unit) and grid size(unit)? Seems like the grid pattern on the Geo tiles are too small...? If I leave my map 5' to 1 unit, the campaign gris isn't lined up with the heavy grid pattern of the Geo tiles. Should it? Thanks
1422999954
The Aaron
Pro
API Scripter
Vince said: I replaced my images in the rollable tables swapping out from local copies on my computer. Any reason to upload them to my library other than to use the images outside of DR? I believe dragging images into a Rollable Table Item will upload them to your Library behind the scenes.
1423000090
The Aaron
Pro
API Scripter
Vince said: Second question, what do you recommend for scale(unit) and grid size(unit)? Seems like the grid pattern on the Geo tiles are too small...? If I leave my map 5' to 1 unit, the campaign gris isn't lined up with the heavy grid pattern of the Geo tiles. Should it? If I remember correctly, the stone flagstones of the images are 1/2 grid sized by default. The grid should line up on every other one.
1423010245
vÍnce
Pro
Sheet Author
Thanks Aaron. I was using the Dev when I did my image swap with the rollable tables... I didn't think about it until I was nearly half-way thru the process. The Dev is funny the way it handles images. Using the upload feature of the library is the only way to get images into your library. Dragging images to the map, using the Favorite(Star) feature in sidebar search, and apparently image features within rollable tables do not add the images to your library on the Dev. Anyhow, Dungeon Ready works fine since all the images are "in" the rollable table I guess. So, I wasn't sure if I also needed to have them in my library as well? You are absolutely right about the Geo tiles being 1/2's After closer inspection, there isn't a "heavy" and light grid pattern. I must have been seeing an optical illusion after importing the images for the script... lol Thanks again.
1423012926
The Aaron
Pro
API Scripter
Ah yeah, dev is certainly different... =D
1423088352

Edited 1423157731
vÍnce
Pro
Sheet Author
Found a cool trick. New to me at Ieast. I thought it would be neat if certain players had control over certain doors. It would be like they have a key for that door. There's probably a better way to do this, I haven't really considered it... Steps to make a key; Make a copy the DungeonReadyDoorControl journal and re-named it "KEY A" and assign control to Player X. Pick your door(s) and using the door token's properties, first copy the current name(id) of the token and change Represents to "KEY A", finally paste the name(id) back in the name field and save. Without the proper id I don't believe the door will function. Now Player X can click on that door and have access to the doors Toggle-Feature macro.
1423144132
Wes
Sheet Author
I never thought of that.... Nice.
1426192645
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Vince said: Found a cool trick. New to me at Ieast. I thought it would be neat if certain players had control over certain doors. It would be like they have a key for that door. There's probably a better way to do this, I haven't really considered it... Steps to make a key; Make a copy the DungeonReadyDoorControl journal and re-named it "KEY A" and assign control to Player X. Pick your door(s) and using the door token's properties, first copy the current name(id) of the token and change Represents to "KEY A", finally paste the name(id) back in the name field and save. Without the proper id I don't believe the door will function. Now Player X can click on that door and have access to the doors Toggle-Feature macro. So that is is slick. Had not considered that.
1426194861

Edited 1426204259
I fixed my original problems, but now I can't seem to get the doors to automatically generate dynamic lighting lines. I have the Readydoors script installed and its successfully changing the tokens, but I can't seem to get it to alter or add to Dynamic Lighting at all. Do I have to do this part manually?
1428255900
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Note this script does not like it when you "Copy/Paste" using "Ctrl c/v Copy/Paste" or "Right Click Copy/Paste"... URLs get broken. Use the token action "Copy/Paste" which looks like this "▓»▓-Paste-Selected"
1428256669
vÍnce
Pro
Sheet Author
Stephen S. said: Note this script does not like it when you "Copy/Paste" using "Ctrl c/v Copy/Paste" or "Right Click Copy/Paste"... URLs get broken. Use the token action "Copy/Paste" which looks like this "▓»▓-Paste-Selected" Can confirm. [School of Hard Knocks]
1430128917
Ziechael
Forum Champion
Sheet Author
API Scripter
Hi Stephen, it's the pest from this thread . I asked about making a script that automatically updated the DL on change of graphic so i could use geomorphic tiles (like these that you kindly directed me to) in a rollable table to make a labyrinth that could be changed as a party adventures in it but keep the DL updated without manual effort (the WORST kind of effort!). You indicated that this script could do that with some simple modifications which I was hoping to achieve myself, however my javascript has been found sorely lacking since i'm very slowly teaching myself it... Do you think an update with the required changes would be of benefit to this script enough to warrant creator intervention? ;) ;) As always, love your work!
1430135920
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
I will try to look at this today. Need to add an event for graphic change.
1430214292
Ziechael
Forum Champion
Sheet Author
API Scripter
Just so you know, there is no rush... i'm planning way ahead with my campaign with this... but if you think it will be an awesome feature that will aid sales then please go ahead ;) Also, i know you can't resist the mental exercise either...
1430219403
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Trying! I was surprised by my Dungeon Draw packs showing up in the "queue" to go live on the market and had to scramble a bit yesterday.
This is so amazing.
1432324119
Ziechael
Forum Champion
Sheet Author
API Scripter
Wandler said: This is so amazing. If you think this is amazing now just wait till Stephen has time to implement an event for updating the DL on graphic change! Dungeons that change on the fly using multi-sided tiles anyone? Perfect if your party has someone who loves to draw out the maps old school while you play ;)
1433420330
Ziechael
Forum Champion
Sheet Author
API Scripter
Ziechael said: Hi Stephen, it's the pest from this thread . I asked about making a script that automatically updated the DL on change of graphic so i could use geomorphic tiles (like these that you kindly directed me to) in a rollable table to make a labyrinth that could be changed as a party adventures in it but keep the DL updated without manual effort (the WORST kind of effort!). You indicated that this script could do that with some simple modifications which I was hoping to achieve myself, however my javascript has been found sorely lacking since i'm very slowly teaching myself it... Do you think an update with the required changes would be of benefit to this script enough to warrant creator intervention? ;) ;) As always, love your work! Just slyly bumping this feature request since you've got some vacation coming up ;)
1433421258
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
I would reallylike to make a cave pack along these lines.
1434963702
Ziechael
Forum Champion
Sheet Author
API Scripter
Ziechael said: Ziechael said: Hi Stephen, it's the pest from this thread . I asked about making a script that automatically updated the DL on change of graphic so i could use geomorphic tiles (like these that you kindly directed me to) in a rollable table to make a labyrinth that could be changed as a party adventures in it but keep the DL updated without manual effort (the WORST kind of effort!). You indicated that this script could do that with some simple modifications which I was hoping to achieve myself, however my javascript has been found sorely lacking since i'm very slowly teaching myself it... Do you think an update with the required changes would be of benefit to this script enough to warrant creator intervention? ;) ;) As always, love your work! Just slyly bumping this feature request since you've got some vacation coming up ;) ^^ Just make sure this thread doesn't die... however I can't do this without seriously skirting the issue of irritating repetition as outlined the Code of Conduct. Therefore, since the thread for your patrol script has closed now i'll enquire about it here: I have installed both the main script and the array but i'm getting an unexpected identfier ) error when attempting to use it... is it a finished product yet? (<a href="https://app.roll20.net/forum/post/1779465/thinking-about-dynamic-lighting-eye-tracking-dot-dot-dot-or-sneaking-up-on-villager-vince-dot#post-1803717" rel="nofollow">https://app.roll20.net/forum/post/1779465/thinking-about-dynamic-lighting-eye-tracking-dot-dot-dot-or-sneaking-up-on-villager-vince-dot#post-1803717</a>)
1434971989
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Ziechael said: Ziechael said: Ziechael said: Hi Stephen, it's the pest from this thread . I asked about making a script that automatically updated the DL on change of graphic so i could use geomorphic tiles (like these that you kindly directed me to) in a rollable table to make a labyrinth that could be changed as a party adventures in it but keep the DL updated without manual effort (the WORST kind of effort!). You indicated that this script could do that with some simple modifications which I was hoping to achieve myself, however my javascript has been found sorely lacking since i'm very slowly teaching myself it... Do you think an update with the required changes would be of benefit to this script enough to warrant creator intervention? ;) ;) As always, love your work! Just slyly bumping this feature request since you've got some vacation coming up ;) ^^ Just make sure this thread doesn't die... however I can't do this without seriously skirting the issue of irritating repetition as outlined the Code of Conduct. Therefore, since the thread for your patrol script has closed now i'll enquire about it here: I have installed both the main script and the array but i'm getting an unexpected identfier ) error when attempting to use it... is it a finished product yet? ( <a href="https://app.roll20.net/forum/post/1779465/thinking-about-dynamic-lighting-eye-tracking-dot-dot-dot-or-sneaking-up-on-villager-vince-dot#post-1803717" rel="nofollow">https://app.roll20.net/forum/post/1779465/thinking-about-dynamic-lighting-eye-tracking-dot-dot-dot-or-sneaking-up-on-villager-vince-dot#post-1803717</a> ) No. I actaully went a different direction. <a href="http://i.imgur.com/AQjbSSQ.png" rel="nofollow">http://i.imgur.com/AQjbSSQ.png</a> A* search algorithm with API. The idea being mobs could find thier own path between points. Test code for that... var pathFinding = pathFinding || (function(){ 'use strict'; var version = '0.1.1', lastUpdate = 1430550687, schemaVersion = '0.1.1', deferred={ batchSize: 30, initialDefer: 10, batchDefer: 10 }, objExtractKeysGraphic = ['id','pageid','layer','width','height','top','left'], objExtractKeysPath = ['id','pageid','layer','width','height','top','left','path','stroke'], // the world grid: a 2d array of tiles world = [[]], currentPath, // size in the world in sprite tiles worldWidth = 25, worldHeight = 25, // size of a tile in pixels tileWidth = 70, tileHeight = 70, currentPageId, heuristic = 'default', // 'default' = default: no diagonals (Manhattan) linear movement - no diagonals - just cardinal directions (NSEW) // 'DiagonalDistance' = diagonals allowed but no sqeezing through cracks diagonal movement - assumes diag dist is 1, same as cardinals // 'DiagonalNeighboursFree' = diagonals and squeezing through cracks allowed // 'EuclideanDistance' = euclidean but no squeezing through cracks // 'EuclideanNeighboursFree' = euclidean and squeezing through cracks allowed // Euclidean: diagonals are considered a little farther than cardinal directions // diagonal movement using Euclide (AC = sqrt(AB^2 + BC^2)) // where AB = x2 - x1 and BC = y2 - y1 and AC will be [x3, y3] deferredCreateObj = (function(){ var queue = [], creator, doCreates = function(){ var done = 0, request; while(queue.length && ++done &lt; deferred.batchSize ){ request = queue.shift(); createObj(request.type,request.properties); } if( queue.length ){ creator = setTimeout(doCreates, deferred.batchDefer ); } else { creator = false; } }; return function(type,properties){ queue.push({type: type, properties: properties}); if(!creator){ creator = setTimeout(doCreates, deferred.initialDefer ); } }; }()), getObjValue = function(obj, keys) { return _.reduce( keys || objExtractKeys, function(m,prop){ m[prop] = obj.get(prop); return m; }, {}); }, createPath = function() { var rp,url; for (rp=0; rp&lt;currentPath.length; rp++) { switch(rp) { case 0: // start url = '<a href="https://s3.amazonaws.com/files.d20.io/images/9372382/64nmkiAegRAKK2t8Oxabhw/thumb.jpg?1431210220" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/9372382/64nmkiAegRAKK2t8Oxabhw/thumb.jpg?1431210220</a>'; break; case currentPath.length-1: // end url = '<a href="https://s3.amazonaws.com/files.d20.io/images/9372379/6jotbaghumajhMmWML3etw/thumb.jpg?1431210213" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/9372379/6jotbaghumajhMmWML3etw/thumb.jpg?1431210213</a>'; break; default: // path node url = '<a href="https://s3.amazonaws.com/files.d20.io/images/9372387/thW1wEVx37CuztiJEQVHYA/thumb.jpg?1431210233" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/9372387/thW1wEVx37CuztiJEQVHYA/thumb.jpg?1431210233</a>'; break; } deferredCreateObj('graphic', { subtype: 'token', pageid: currentPageId, layer: 'map', width: 70, height: 70, left: (currentPath[rp][0] * 70) + 35, top: (currentPath[rp][1] * 70) + 35, imgsrc: url }); } }, createWorld = function(){ var x,y,url,pathStart,pathEnd; // create emptiness for (x = 0; x &lt; worldWidth; x = x + 1) { world[x] = []; for (y = 0; y &lt; worldHeight; y = y + 1) { world[x][y] = 0; } } // scatter some walls for (x = 0; x &lt; worldWidth; x = x + 1) { for (y = 0; y &lt; worldHeight; y = y + 1) { if (Math.random() &gt; 0.75) { world[x][y] = 1; } } } currentPath = []; while (currentPath.length == 0) { pathStart = [Math.floor(Math.random()*worldWidth),Math.floor(Math.random()*worldHeight)]; pathEnd = [Math.floor(Math.random()*worldWidth),Math.floor(Math.random()*worldHeight)]; if (world[pathStart[0]][pathStart[1]] == 0) currentPath = findPath(world,pathStart,pathEnd); } for (x = 0; x &lt; worldWidth; x = x + 1) { for (y = 0; y &lt; worldHeight; y = y + 1) { switch(world[x][y]) { case 1: url = '<a href="https://s3.amazonaws.com/files.d20.io/images/9372233/WEb5s4bsLY_MNI2tr2NE2A/thumb.jpg?1431209718" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/9372233/WEb5s4bsLY_MNI2tr2NE2A/thumb.jpg?1431209718</a>'; break; default: url = '<a href="https://s3.amazonaws.com/files.d20.io/images/9372122/PI3s2Q7sJbGO3sqJLf3lWQ/thumb.jpg?1431209428" rel="nofollow">https://s3.amazonaws.com/files.d20.io/images/9372122/PI3s2Q7sJbGO3sqJLf3lWQ/thumb.jpg?1431209428</a>'; break; } deferredCreateObj('graphic', { subtype: 'token', pageid: currentPageId, layer: 'map', width: 70, height: 70, left: (x * 70) + 35, top: (y * 70) + 35, imgsrc: url }); } } createPath(); }, // world is a 2d array of integers (eg world[10][15] = 0) // pathStart and pathEnd are arrays like [5,10] findPath = function(world, pathStart, pathEnd) { // shortcuts for speed var abs = Math.abs, max = Math.max, pow = Math.pow, sqrt = Math.sqrt, distanceFunction, findNeighbours, /* The world data are integers: anything higher than this number is considered blocked this is handy is you use numbered sprites, more than one of which is walkable road, grass, mud, etc */ maxWalkableTileNum = 0, /* Keeps track of the world dimensions. Note that this A-star implementation expects the world array to be square: it must have equal height and width. If your game world is rectangular,just fill the array with dummy values to pad the empty space. */ worldWidth = world[0].length, worldHeight = world.length, worldSize = worldWidth * worldHeight; //Which heuristic should we use? switch(heuristic){ case 'DiagonalDistance': distanceFunction = DiagonalDistance; findNeighbours = DiagonalNeighbours; break; case 'DiagonalNeighboursFree': distanceFunction = DiagonalDistance; findNeighbours = DiagonalNeighboursFree; break; case 'EuclideanDistance': distanceFunction = EuclideanDistance; findNeighbours = DiagonalNeighbours; break; case 'EuclideanNeighboursFree': distanceFunction = EuclideanDistance; findNeighbours = DiagonalNeighboursFree; break; default: distanceFunction = ManhattanDistance; findNeighbours = function(){}; break; } function ManhattanDistance(Point, Goal) { return abs(Point.x - Goal.x) + abs(Point.y - Goal.y); } function DiagonalDistance(Point, Goal) { return max(abs(Point.x - Goal.x), abs(Point.y - Goal.y)); } function EuclideanDistance(Point, Goal) { return sqrt(pow(Point.x - Goal.x, 2) + pow(Point.y - Goal.y, 2)); } // Neighbours functions, used by findNeighbours function // to locate adjacent available cells that aren't blocked // Returns every available North, South, East or West // cell that is empty. No diagonals, // unless distanceFunction function is not Manhattan function Neighbours(x, y) { var N = y - 1, S = y + 1, E = x + 1, W = x - 1, myN = N &gt; -1 && canWalkHere(x, N), myS = S &lt; worldHeight && canWalkHere(x, S), myE = E &lt; worldWidth && canWalkHere(E, y), myW = W &gt; -1 && canWalkHere(W, y), result = []; if(myN) {result.push({x:x, y:N}); } if(myE) {result.push({x:E, y:y}); } if(myS) {result.push({x:x, y:S}); } if(myW) {result.push({x:W, y:y}); } findNeighbours(myN, myS, myE, myW, N, S, E, W, result); return result; } // returns every available North East, South East, // South West or North West cell - no squeezing through // "cracks" between two diagonals function DiagonalNeighbours(myN, myS, myE, myW, N, S, E, W, result) { if(myN) { if(myE && canWalkHere(E, N)) result.push({x:E, y:N}); if(myW && canWalkHere(W, N)) result.push({x:W, y:N}); } if(myS) { if(myE && canWalkHere(E, S)) result.push({x:E, y:S}); if(myW && canWalkHere(W, S)) result.push({x:W, y:S}); } } // returns every available North East, South East, // South West or North West cell including the times that // you would be squeezing through a "crack" function DiagonalNeighboursFree(myN, myS, myE, myW, N, S, E, W, result){ myN = N &gt; -1; myS = S &lt; worldHeight; myE = E &lt; worldWidth; myW = W &gt; -1; if(myE) { if(myN && canWalkHere(E, N)) {result.push({x:E, y:N}); } if(myS && canWalkHere(E, S)) {result.push({x:E, y:S}); } } if(myW) { if(myN && canWalkHere(W, N)) {result.push({x:W, y:N}); } if(myS && canWalkHere(W, S)) {result.push({x:W, y:S}); } } } // returns boolean value (world cell is available and open) function canWalkHere(x, y) { return ((world[x] != null) && (world[x][y] != null) && (world[x][y] &lt;= maxWalkableTileNum)); } // Node function, returns a new object with Node properties // Used in the calculatePath function to store route costs, etc. function Node(Parent, Point) { var newNode = { // pointer to another Node object Parent:Parent, // array index of this Node in the world linear array value:Point.x + (Point.y * worldWidth), // the location coordinates of this Node x:Point.x, y:Point.y, // the heuristic estimated cost // of an entire path using this node f:0, // the distanceFunction cost to get // from the starting point to this node g:0 }; return newNode; } // Path function, executes AStar algorithm operations function calculatePath() { // create Nodes from the Start and End x,y coordinates var mypathStart = Node(null, {x:pathStart[0], y:pathStart[1]}); var mypathEnd = Node(null, {x:pathEnd[0], y:pathEnd[1]}); // create an array that will contain all world cells var AStar = new Array(worldSize); // list of currently open Nodes var Open = [mypathStart]; // list of closed Nodes var Closed = []; // list of the final output array var result = []; // reference to a Node (that is nearby) var myNeighbours; // reference to a Node (that we are considering now) var myNode; // reference to a Node (that starts a path in question) var myPath; // temp integer variables used in the calculations var length, max, min, i, j; // iterate through the open list until none are left while(length = Open.length) { max = worldSize; min = -1; for(i = 0; i &lt; length; i++) { if(Open[i].f &lt; max) { max = Open[i].f; min = i; } } // grab the next node and remove it from Open array myNode = Open.splice(min, 1)[0]; // is it the destination node? if(myNode.value === mypathEnd.value) { myPath = Closed[Closed.push(myNode) - 1]; do { result.push([myPath.x, myPath.y]); } while (myPath = myPath.Parent); // clear the working arrays AStar = Closed = Open = []; // we want to return start to finish result.reverse(); } else {// not the destination // find which nearby nodes are walkable myNeighbours = Neighbours(myNode.x, myNode.y); // test each one that hasn't been tried already for(i = 0, j = myNeighbours.length; i &lt; j; i++) { myPath = Node(myNode, myNeighbours[i]); if (!AStar[myPath.value]) { // estimated cost of this particular route so far myPath.g = myNode.g + distanceFunction(myNeighbours[i], myNode); // estimated cost of entire guessed route to the destination myPath.f = myPath.g + distanceFunction(myNeighbours[i], mypathEnd); // remember this new path for testing above Open.push(myPath); // mark this node in the world graph as visited AStar[myPath.value] = true; } } // remember this route as having no more untested options Closed.push(myNode); } } // keep iterating until the Open list is empty return result; } // actually calculate the a-star path! // this returns an array of coordinates // that is empty if no path is possible return calculatePath(); }, // end of findPath() function refreshData = function(){ var page = getObj('page', Campaign().get('playerpageid')); currentPageId = page.get('id'); worldWidth = page.get('width'); worldHeight = page.get('height'); }, checkInstall = function() { if( ! _.has(state,'pathFinding') || state.pathFinding.version !== schemaVersion) { log('pathFinding: Resetting state'); state.pathFinding = { version: schemaVersion }; } }, handleGraphicChange = function(obj) { var objValues = getObjValue(obj, objExtractKeysGraphic); }, handlePathAdd = function(obj) { var objValues = getObjValue(obj, objExtractKeysPath); }, handlePageChange = function(obj) { if ( Campaign().get('playerpageid') !== currentPageId ) { refreshData(); } }, handleInput = function(msg) { var message = _.clone(msg), messageArguments; if ( 'api' !== message.type ) { return; } refreshData(); createWorld(); }, registerEventHandlers = function() { on('change:graphic', handleGraphicChange); on('add:path', handlePathAdd); on('change:campaign:playerpageid', handlePageChange); on('chat:message', handleInput); checkInstall(); }; return { CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers }; }()); on('ready',function(){ 'use strict'; pathFinding.RegisterEventHandlers(); });
1434972796
Ziechael
Forum Champion
Sheet Author
API Scripter
Ahh, i remember seeing that particular brain leak elsewhere, you are hard to keep up with though ;) I'm looking to use something like this to have some magic light orbs rotate around a room continually... is this test code stable enough to play with at present?
1434976213

Edited 1434976246
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Ziechael said: Ahh, i remember seeing that particular brain leak elsewhere, you are hard to keep up with though ;) I'm looking to use something like this to have some magic light orbs rotate around a room continually... is this test code stable enough to play with at present? Like willo the wisps... We have mapping (Dungeon Draw or something like it.) We have the basic A* search algorithm. What I need and, what I am working on is encoding the map into a very small data set. Aaron gave me a suggestion I am working on and that is "run-length encoding" If i get that going we can share map designs (you share how the tiles should be arranged and not the tiles) or have wandering that can read the map and therefore move about randomly or between waypoints. That code I posted doesn't get us there yet... so not sure how useful it right now.
I know this may be a dumb question but where do I find the macros that need to be made.
1435061801
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
You should be able to find them here: <a href="https://wiki.roll20.net/Macros#Macro_Bar" rel="nofollow">https://wiki.roll20.net/Macros#Macro_Bar</a>
1435063789
Ziechael
Forum Champion
Sheet Author
API Scripter
Stephen S. said: Ziechael said: I'm looking to use something like this to have some magic light orbs rotate around a room continually... is this test code stable enough to play with at present? Like willo the wisps... That's essentially the effect i'm looking to create yes =D Harking back to my original reason for becoming your personal stalker am i right in thinking that ' Need to add an event for graphic change. ' in order to get the DL to update if i used the tiles from this script as part of a rollable table is effectively as simple as adding a function that reapplies the DL part of the script when it recognises a graphic change? (i'm trying to teach myself Java and while it is very slow going i'm looking forward to see how you would implement this).
1435067037
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Yeah. I just started a random generator of the space/industy geos . <a href="https://gist.github.com/BaldarSilveraxe/520f41972b" rel="nofollow">https://gist.github.com/BaldarSilveraxe/520f41972b</a>... It has what you are looking for....I need to go back and update all my scripts that are pre- obj.remove(); I will try to do that this weekend. I have one other project I am working to complete that is map sharing for Dungeon Draw. The idea is someone makes a map like this (sort of a simple Inn.) And then they share a Gist with information like this: DungeonDesign['Simple Inn'] = '1BB1 1AB2 1BC3 1BB4 1AB5 1BC6 1BB7 1AB8 1BC9 1BB10 1BC11 ' +'2AA1 2FA2 2AC3 2AA4 2FA5 2AC6 2AA7 2FA8 2AC9 2AA10 2AC11 ' +'3BA1 3KA2 3AC3 3BA4 3KA5 3AC6 3BA7 3KA8 3AC9 3AA10 3AC11 ' +'4BB1 4KB2 4KC3 4AB4 4KB5 4KC6 4AB7 4KB8 4KC9 4KB10 4AC11 ' +'5BA1 5LD2 5AD3 5AD4 5LD5 5AD6 5AD7 5LD8 5AD9 5KA10 5AC11 ' +'6BB1 6LB2 6BC3 6BB4 6LB5 6BC6 6BB7 6LB8 6BC9 6AA10 6AC11 ' +'7AA1 7FA2 7AC3 7AA4 7FA5 7AC6 7AA7 7FA8 7AC9 7AA10 7AC11 ' +'8BA1 8AD2 8BD3 8BA4 8AD5 8BD6 8BA7 8AD8 8BD9 8BA10 8BD11 ' +'11BB1 11AB2 11AB3 11AB4 11AB5 11AB6 11AB7 11AB8 11AB9 11AB10 11BC11 11AB12 11BC13 11AB14 11AB15 11AB16 11AB17 11AB18 11AB19 11BC20 ' +'12AA1 12FA2 12FA3 12FA4 12FA5 12FA6 12FA7 12FA8 12FA9 12FA10 12AC11 12FA12 12AC13 12KA14 12FA15 12FA16 12FA17 12FA18 12FA19 12AC20 ' +'13AA1 13FA2 13FA3 13FA4 13FA5 13FA6 13FA7 13FA8 13FA9 13FA10 13KC11 13AB12 13AB13 13KB14 13FA15 13FA16 13FA17 13FA18 13FA19 13AC20 ' +'14AA1 14FA2 14FA3 14FA4 14KD5 14AD6 14KA7 14FA8 14FA9 14FA10 14FA11 14KD12 14AD13 14KA14 14FA15 14FA16 14FA17 14FA18 14FA19 14AC20 ' +'15AA1 15FA2 15FA3 15FA4 15AC5 15QA6 15AA7 15FA8 15FA9 15FA10 15FA11 15AC12 15QA13 15AA14 15FA15 15FA16 15FA17 15FA18 15FA19 15AC20 ' +'16AA1 16FA2 16FA3 16FA4 16KC5 16AB6 16KB7 16FA8 16FA9 16FA10 16FA11 16KC12 16AB13 16KB14 16FA15 16FA16 16FA17 16FA18 16FA19 16AC20 ' +'17AA1 17FA2 17FA3 17FA4 17FA5 17FA6 17FA7 17FA8 17FA9 17FA10 17FA11 17FA12 17FA13 17FA14 17FA15 17FA16 17FA17 17FA18 17FA19 17AC20 ' +'18BA1 18AD2 18AD3 18AD4 18AD5 18AD6 18AD7 18AD8 18AD9 18AD10 18AD11 18AD12 18AD13 18AD14 18AD15 18AD16 18AD17 18AD18 18AD19 18BD20'; You add it to a an API script that holds maps designs.... You can then call up a map someone else designed... with a "click'"... all drawn, walled and lighted. Blueprint sharing... basically.
1435069306
Ziechael
Forum Champion
Sheet Author
API Scripter
I noticed you mention that in another thread, i can see it being really useful! Love your work, plain and simple!
This is my favorite tool :D &lt;3
1439134124

Edited 1439738666
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Thanks. I had fun making these..