Advertisement Create a free account

[Script] Random Dungeon Generator with Dynamic Lighting

1392521728

Edited 1413576111
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
https://marketplace.roll20.net/browse/set/252/old-... Tile pack... https://wiki.roll20.net/Random_Dungeon_Generator New GIST https://gist.github.com/BaldarSilveraxe/9073aa3116...
1392521865
Konrad J.
Pro
API Scripter
Cool, I gotta try this. I'll wait for your walkthrough. Don't forget to show an example screen shot of the output!
The !geo function works perfectly.. and it is far more usable than previous iterations. Congrats! I think I missed how to set up the lighting for now (despite the fact that it doesn't function properly). Is there something I need to place on line 866 where it has "obj.path"? Currently when I try to use !light, I get this:
1392565234
Looks really cool but I tried it and nothing shows up except: "API: GeomorphicMap has images on it." Though no pictures are showing, the lighting script seems to work.
1392566583

Edited 1392567123
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
markus l. said: Looks really cool but I tried it and nothing shows up except: "API: GeomorphicMap has images on it." Though no pictures are showing, the lighting script seems to work. You need to to check all layers. And it is possible an "off" map image exist (something was moved beyond the edges of the map.... the object exists but you can't see it because it is "out of bounds.") In the case of the later... Create a new map and name it "GeomorphicMap" and delete your old map or rename it to something else.
1392567032
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Jarrod . said: The !geo function works perfectly.. and it is far more usable than previous iterations. Congrats! I think I missed how to set up the lighting for now (despite the fact that it doesn't function properly). Is there something I need to place on line 866 where it has "obj.path"? Currently when I try to use !light, I get this: readMap = function() { var campaignPagesGeo = findObjs({ name: mapName, _type: "page"}); geomorphicMapId = campaignPagesGeo[0].get("_id"); var currentPageGraphics = findObjs({ _pageid: geomorphicMapId, layer: "map" }); var lightArray = new Array(); _.each(currentPageGraphics, function(obj) { pathData = _.where(geomorphicTilesArray, {side: obj.get("currentSide")}); lightArray.push({ currentSide: obj.get("currentSide"), left: obj.get("left"), top: obj.get("top"), rotation: obj.get("rotation"), path: pathData[0].walls }); }); log(lightArray) /* _.each(lightArray, function(obj) { createObj("path",{ layer: "walls", _path: obj.path, width: 840, height: 840, top: obj.top, left: obj.left, rotation: obj.rotation, stroke: "#00ff00", pageid: geomorphicMapId }); }); */ }; Add the three lines in "BOLD" "log(lightArray)" a nd the start of comments "/*" and the end of comments "*/" This will disable the "_each loop" and give you a readout of the lightArray in the API Output Console... post that and we can see what is happening in that array.
1392567973
Thanks for the quick reply! I went through all layers, drawing a doodle on each and selecting everything on the layer with ctrl+A and there doesn't seem to be anything off screen. Doesn't work when I retry on a new map. When you say "You need to to check all layers.", is that a toggle of some kind or just looking at each layer? I redid everything on a fresh campaign and I can't make it work there either.
ok, so... after re-entering the script (deleting it and copying and pasting the script again) both !geo and !light work.. and looking at how the lighting is set up, I'm wondering if the way the Lighting lines are listed in the array, if it's making smaller polygons on the map instead of setting the paths to be the barriers. Here's a shot of what I mean
1392569856

Edited 1392570801
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
markus l. said: Thanks for the quick reply! I went through all layers, drawing a doodle on each and selecting everything on the layer with ctrl+A and there doesn't seem to be anything off screen. Doesn't work when I retry on a new map. When you say "You need to to check all layers.", is that a toggle of some kind or just looking at each layer? I redid everything on a fresh campaign and I can't make it work there either. To check all layers I mean this: Or you can disable the scripts and create a new one in another tab like this: on("ready", function() { on("chat:message", function(msg) {if(msg.type == "api"){processMessage(msg)};}); }); processMessage = function(msg) { if(msg.type !== "api"){return}; var mapName = "GeomorphicMap"; var campaignPagesGeo = findObjs({ name: mapName, _type: "page"}); geomorphicMapId = campaignPagesGeo[0].get("_id"); var currentPageGraphics = findObjs({ _pageid: geomorphicMapId}); log(currentPageGraphics) }; Enter !test as an API command (or any API command) and see what is placed in the API Output Console. Something has to be there because the find object is finding something.. You could also add a log here: mapCheck = function() { var campaignPagesGeo = findObjs({ name: mapName, _type: "page"}); if(campaignPagesGeo.length == 0){isError = true; errorType = mapName + " is missing."; return;}; if(campaignPagesGeo.length > 1){isError = true; errorType = "More than one " + mapName + "."; return;}; geomorphicMapId = campaignPagesGeo[0].get("_id"); var geomorphicMapGraphics = findObjs({_pageid: geomorphicMapId, _type: "graphic"}); if(geomorphicMapGraphics.length != 0){isError = true; errorType = mapName + " has images on it."; return;}; var geomorphicMapGraphics = findObjs({_pageid: geomorphicMapId, _type: "path"}); if(geomorphicMapGraphics.length != 0){isError = true; errorType = mapName + " has paths on it."; return;}; geomorphicMapWidth = campaignPagesGeo[0].get("width"); geomorphicMapHeight = campaignPagesGeo[0].get("height"); if(geomorphicMapWidth % 12 !== 0){isError = true; errorType = "Map width must be disible by 12."; return;}; if(geomorphicMapHeight % 12 !== 0){isError = true; errorType = "Map height must be disible by 12."; return;}; if(geomorphicMapWidth < 36 || geomorphicMapHeight < 36){isError = true; errorType = "Map height must be 36 or larger."; return;}; log(geomorphicMapGraphics) }; See the "BOLD" code log(geomorphicMapGraphics) ... add it around line 584 in the Gist.
1392570398
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Jarrod . said: ok, so... after re-entering the script (deleting it and copying and pasting the script again) both !geo and !light work.. and looking at how the lighting is set up, I'm wondering if the way the Lighting lines are listed in the array, if it's making smaller polygons on the map instead of setting the paths to be the barriers. Here's a shot of what I mean Yea its one object with several lines and they get interpreted in a weird way. Rather then having one object for the "Geo_Type_A_0019" tile that has a path like this: "[\[\"M\",315,595],[\"L\",245,595],[\"L\",245,245],[\"L\",595,245],[\"L\",595,595],[\"L\",525,595],\[\"M\",315,0],[\"L\",315,35],[\"L\",525,35],[\"L\",525,0],\ [\"M\",840,105],[\"L\",805,105],[\"L\",805,35],[\"L\",735,35],[\"L\",735,0],\[\"M\",0,105],[\"L\",35,105],[\"L\",35,35],[\"L\",105,35],[\"L\",105,0],\ [\"M\",0,315],[\"L\",35,315],[\"L\",35,525],[\"L\",0,525],\ [\"M\",840,315],[\"L\",805,315],[\"L\",805,525],[\"L\",840,525],\ [\"M\",0,735],[\"L\",35,735],[\"L\",35,805],[\"L\",105,805],[\"L\",105,840],\ [\"M\",840,735],[\"L\",805,735],[\"L\",805,805],[\"L\",735,805],[\"L\",735,840],\ [\"M\",315,840],[\"L\",315,805],[\"L\",525,805],[\"L\",525,840]\]"; Each start of "M" would be its own object with its own path... tricky part is you have to find the center of each path and relate it to the center of the tile and turn it around that point based on rotation. That should fix it... it will just take time building a function to do that for whatever paths are fed into it. Want this to support any geomorphic tiles that get created... then we can just feed them in as we like and get really quick on the fly maps. Would like to get door creation based on Matt's work as well and random mob population based on room size.
1392572465
"ERROR: You cannot set the imgsrc or avatar of an object unless you use an image that is in your Roll20 Library. See the API documentation for more info." is what it says in the API Output Console, I guess it references your map tiles that I have bought, I tried logging out and in again to see if it would update but it didn't.
1392573703

Edited 1392573744
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
The images sources and path are all pulled from the rollable table so that error should no be occurring. This drives the script.... geomorph = function() { mapCheck(); checkTileTable(); buildTileArray(); gridOutMap(); createSides(); if(isError == true){sendChat("API", errorType); isError = false; return;}; placeCorners(); placeEdge(); fillFrame(); setSpin(); stepThroughMap(); }; The functions are pretty sequential... so you can comment out each one and step through it. mapCheck(); looks for one map with no images that is size properly. checkTileTable(); just checks the roll able table vs the hard coded array . buildTileArray(); creates the array for managing the images. gridOutMap(); creates an array to track which tile goes where and with what rotation. createSides(); just makes a string to be used for manual image swaps After the rest is just using that information gathered in arrays to make the map. So try something like this and just advance through each step by moving the "/*Only functions above this will run" down a row. geomorph = function() { mapCheck(); /*Only functions above this will run checkTileTable(); buildTileArray(); gridOutMap(); createSides(); if(isError == true){sendChat("API", errorType); isError = false; return;}; placeCorners(); placeEdge(); fillFrame(); setSpin(); stepThroughMap(); */ }; Get the MapCheck(); working without error and then the next. If you get past createSides(); then everything should run just fine.
1392574001
Alright thanks! But if this doesn't work either would it be possible for you to make an campaign that I could copy that has everything working?
1392574240

Edited 1392574268
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
https://app.roll20.net/join/312353/oDPHOg Let me know and I will make you a GM there.
1392574819

Edited 1392575061
It stops working when I allow: "if(isError == true){sendChat("API", errorType); isError = false; return;};" *Or it starts showing the error message geomorphicmap is missing **NVM I messed that up, trying again!
1392574982

Edited 1392575250
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Skip that.... its not really needed and see what else works. Made you a GM in that campaign BTW.
1392575406

Edited 1392575430
OK so when I allowed the last line "stepThroughMap();" that's when it starts saying that there already are images on the map and also "ERROR: You cannot set the imgsrc or avatar of an object unless you use an image that is in your Roll20 Library. See the API documentation for more info." *Thanks :)
Ah, I see. Maybe Matt may be able to offer a little input? Also, I think that door generation like Matt's door toggle script included for all the opening areas would be amazing (setting it to true or false to turn the feature on or off).. This, despite proving to have some painful aspects, is looking like one of the most useful scripts you can use. Maybe I'll have to see about making some more geomorphic tiles.
1392576525
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
markus l. said: OK so when I allowed the last line "stepThroughMap();" that's when it starts saying that there already are images on the map and also "ERROR: You cannot set the imgsrc or avatar of an object unless you use an image that is in your Roll20 Library. See the API documentation for more info." *Thanks :) Yea that actually places the tiles. Can you place tokens from your rollable table? Because those URLs are the exact same URLs being used.
1392576832

Edited 1392576945
If I press Token on the rollable table then yes, a picture pops up but it's always the 0001 map tile *Drag and dropping from the opened table doesn't work
1392577063

Edited 1392577079
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
You can change the occurrence to 1000 for each one and step through it. But that is a pain.... let me make a scrip to just "test" the set up and I will post it later.
1392630421
Alex L.
Pro
Sheet Author
Code for Creating individual lines + rotation. You will need to add offsets to the Top and left to position them correctly (this only works for a single tile). dynamicLighting = [ [315,595], [245,595], [245,245], [595,245], [595,595], [525,595] ]; function rot(angle, point) { var pointX = point[0], pointY = point[1], originX = 70*6, originY = 70*6; angle = angle * Math.PI / 180.0; return [ Math.cos(angle) * (pointX-originX) - Math.sin(angle) * (pointY-originY) + originX, Math.sin(angle) * (pointX-originX) + Math.cos(angle) * (pointY-originY) + originY ]; } //Put this somewhere, I use on ready. var h = 0; var l = false; var h2 = 0; var l2 = false; for(var i = 0; i < dynamicLighting.length; i++) { dynamicLighting[i] = rot(90, dynamicLighting[i]); } var p = "[\[\"M\"," + dynamicLighting[0][0] + "," + dynamicLighting[0][1] + "]"; for(var i = 0; i < dynamicLighting.length; i++) { if(i != 0) { p += ",[\"L\"," + dynamicLighting[i][0] + "," + dynamicLighting[i][1] + "]"; } if(dynamicLighting[i][0] > h) h = dynamicLighting[i][0]; if(!l || dynamicLighting[i][0] < l) l = dynamicLighting[i][0]; if(dynamicLighting[i][1] > h2) h2 = dynamicLighting[i][1]; if(!l2 || dynamicLighting[i][1] < l2) l2 = dynamicLighting[i][1]; } p += "\]"; var w = h - l; var hi = h2 - l2; var t = l2 + (hi/2); var le = l + (w/2); createObj("path",{ layer: "walls", _path: p, width: w, height: hi, top: t, left: le, rotation: 0, stroke: "#00ff00", pageid: Campaign().get("playerpageid") });
1392638442
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Alex L. said: Code for Creating individual lines + rotation. You will need to add offsets to the Top and left to position them correctly (this only works for a single tile). dynamicLighting = [ [315,595], [245,595], [245,245], [595,245], [595,595], [525,595] ]; function rot(angle, point) { var pointX = point[0], pointY = point[1], originX = 70*6, originY = 70*6; angle = angle * Math.PI / 180.0; return [ Math.cos(angle) * (pointX-originX) - Math.sin(angle) * (pointY-originY) + originX, Math.sin(angle) * (pointX-originX) + Math.cos(angle) * (pointY-originY) + originY ]; } //Put this somewhere, I use on ready. var h = 0; var l = false; var h2 = 0; var l2 = false; for(var i = 0; i < dynamicLighting.length; i++) { dynamicLighting[i] = rot(90, dynamicLighting[i]); } var p = "[\[\"M\"," + dynamicLighting[0][0] + "," + dynamicLighting[0][1] + "]"; for(var i = 0; i < dynamicLighting.length; i++) { if(i != 0) { p += ",[\"L\"," + dynamicLighting[i][0] + "," + dynamicLighting[i][1] + "]"; } if(dynamicLighting[i][0] > h) h = dynamicLighting[i][0]; if(!l || dynamicLighting[i][0] < l) l = dynamicLighting[i][0]; if(dynamicLighting[i][1] > h2) h2 = dynamicLighting[i][1]; if(!l2 || dynamicLighting[i][1] < l2) l2 = dynamicLighting[i][1]; } p += "\]"; var w = h - l; var hi = h2 - l2; var t = l2 + (hi/2); var le = l + (w/2); createObj("path",{ layer: "walls", _path: p, width: w, height: hi, top: t, left: le, rotation: 0, stroke: "#00ff00", pageid: Campaign().get("playerpageid") }); This is perfect.... and what is needed. As you said... need the offset and the offset as it is rotated.
Just curious.. Are the random tiles to fill the center all defaulted as the normal orientation, or do they have a randomized rotation?
1392654747
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Jarrod . said: Just curious.. Are the random tiles to fill the center all defaulted as the normal orientation, or do they have a randomized rotation? For corners and edges.... the API needs to know the normal orientation of the tile.... and that normal orientation should be like this: So in the geomorphicTilesInformation array we set the tiles to this orientation because we don't know how the content creator will create the tile... example: var geomorphicTilesInformation = [ ...... {tileName:" Geo_Type_A_0025 ", edge: false, corner: true, entrance: false, type: "d", rotation: 180 , rarity: 100, blocked: false}, {tileName: " Geo_Type_A_0026 ", edge: true, corner: false, entrance: false, type: "d", rotation: 270 , rarity: 100, blocked: false}, ..... That is what the rotation value defines... and you only need it for corners and edges... so the API places them properly around the edges. Geo_Type_A_0025 on the left will "start" at 180 degrees of ration... that normalizes it for the API. Geo_Type_A_0026 on the right will "start" at 270 degrees of ration... that normalizes it for the API. Any other tile will be "spun" randomly.... so long as it is 100% geometric. Geo_Type_A_0043 is one of the few non-geometric and its not randomly placed... because it intended to be used beside itself. (Gives the GM that "Bridge of Khazad-dûm" sort of thing.) So all files that can be randomly placed are are randomly "spun"..... Rails and sewers place sides any other tile fine...and therefore are "spun"... but they do have they own preferred orientation which the API currently does not consider (that will be added later.)
1392659243

Edited 1392661916
Alex L.
Pro
Sheet Author
Stephen S. said: Alex L. said: Code for Creating individual lines + rotation. You will need to add offsets to the Top and left to position them correctly (this only works for a single tile). This is perfect.... and what is needed. As you said... need the offset and the offset as it is rotated. No I have handled all the rotation, it creates the paths in a 840 area (ie one tile), you just need to add an offset to the top and left to indicate where the tile is on the map, so for istance if the tile is the 4th tile in from the left you would add 840*4 to the left value.
@stephen- thanks for that explanation. That makes a lot of sense. :) @alex- you and Stephen are a power team! I can't wait to see what kind of stuff you two are going to come up with next!
1392661846

Edited 1392664864
Alex L.
Pro
Sheet Author
Here is the code better fleshed out with a bug fixed (i forgot that 0 == false but doesnt === false), with working example (this will work without editing). var dynamicLighting = [ [[315,595],[245,595],[245,245],[595,245],[595,595],[525,595]], [[315,0],[315,35],[525,35],[525,0]], [[840,105],[805,105],[805,35],[735,35],[735,0]], [[0,105],[35,105],[35,35],[105,35],[105,0]], [[0,315],[35,315],[35,525],[0,525]], [[840,315],[805,315],[805,525],[840,525]], [[0,735],[35,735],[35,805],[105,805],[105,840]], [[840,735],[805,735],[805,805],[735,805],[735,840]], [[315,840],[315,805],[525,805],[525,840]] ]; function rot(angle, point) { var pointX = point[0], pointY = point[1], originX = 70*6, originY = 70*6; // total tile size is 12^2 squares = (12^2)*70 pixels, origin is the point that we rotate around. angle = angle * Math.PI / 180.0; return [ Math.cos(angle) * (pointX-originX) - Math.sin(angle) * (pointY-originY) + originX, Math.sin(angle) * (pointX-originX) + Math.cos(angle) * (pointY-originY) + originY ]; } function createPath(inputPath, angle, Xoffset, Yoffset) { var PathArray = []; // use a god dam copy you n00b :P if(!angle) angle = 0; if(!Xoffset) Xoffset = 0; if(!Yoffset) Yoffset = 0; //use these to work our how big the path is. var maxX = 0; var minX = false; var maxY = 0; var minY = false; //find the min and max X and Y. for(var i = 0; i < inputPath.length; i++) { if(inputPath[i][0] > maxX) maxX = inputPath[i][0]; if(minX === false || Number(inputPath[i][0]) < Number(minX)) minX = inputPath[i][0]; if(inputPath[i][1] > maxY) maxY = inputPath[i][1]; if(minY === false || inputPath[i][1] < minY) minY = inputPath[i][1]; PathArray.push([inputPath[i][0], inputPath[i][1]]); } //work out the size and position the object within the 12^2 area. var objectWidth = maxX - minX; var objectHeight = maxY - minY; var objectTop = minY + (objectHeight/2); var objectLeft = minX + (objectWidth/2); //Rotate the cords in the array and fix array to remove positioning. for(var i = 0; i < PathArray.length; i++) { PathArray[i][0] = PathArray[i][0] - objectLeft + (objectWidth/2); PathArray[i][1] = PathArray[i][1] - objectTop + (objectHeight/2); PathArray[i] = rot(angle, PathArray[i]); } //Convert the array to a string. var pathString = ""; for(var i = 0; i < PathArray.length; i++) { if(i != 0) { pathString += ",[\"L\"," + PathArray[i][0] + "," + PathArray[i][1] + "]"; } else { pathString = "[\[\"M\"," + PathArray[i][0] + "," + PathArray[i][1] + "]"; } } pathString += "\]"; objectTop = objectTop + Yoffset; //offset should be the relative position from the top left in multiples of 840. objectLeft = objectLeft + Xoffset; createObj("path",{ layer: "walls", _path: pathString, width: objectWidth, height: objectHeight, top: objectTop, left: objectLeft, rotation: 0, stroke: "#00ff00", pageid: Campaign().get("playerpageid") }); //You may need to change the page id. } on("ready", function() { //Create a tile at 0,0 with no rotation. for(var i = 0; i < dynamicLighting.length; i++) { createPath(dynamicLighting[i]); } //create the same tile at 0,1 with 90 rotation. for(var i = 0; i < dynamicLighting.length; i++) { createPath(dynamicLighting[i], 90, 1*840, 0); } });
1392664190
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Jarrod . said: @stephen- thanks for that explanation. That makes a lot of sense. :) @alex- you and Stephen are a power team! I can't wait to see what kind of stuff you two are going to come up with next! :P Alex is saving me from my reach exceeding my grasp! Updated the script so the paths are their own object... Will work Alex's stuff into the !light action which goes to this function: setPaths = function() { readMap(); log(pathArray); }; created pathArray for each random map now looks like this for a small random map... (in part, not posting the entire array) ....{"left":420,"top":420,"rotation":180,"path":"[[840,735],[805,735],[805,805],[735,805],[735,840]]"}, {"left":420,"top":420,"rotation":180,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":420,"rotation":180,"path":"[[0,315],[35,315],[35,385],[385,385],[385,35],[315,35],[315,0]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[840,735],[805,735],[805,805],[735,805],[735,840]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[315,840],[315,805],[385,805],[385,315]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,735],[35,735],[35,805],[105,805],[105,840]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,525],[35,525],[35,315]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,315],[35,315],[385,315],[385,35],[315,35],[315,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[805,420],[400,805]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[315,0],[315,35],[525,35],[525,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[840,105],[805,105],[805,35],[735,35],[735,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[0,315],[35,315],[35,525],[0,525]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[840,315],[805,315],[805,525],[840,525]]"}....
1392664974
Alex L.
Pro
Sheet Author
Stephen S. said: Jarrod . said: @stephen- thanks for that explanation. That makes a lot of sense. :) @alex- you and Stephen are a power team! I can't wait to see what kind of stuff you two are going to come up with next! :P Alex is saving me from my reach exceeding my grasp! Updated the script so the paths are their own object... Will work Alex's stuff into the !light action which goes to this function: setPaths = function() { readMap(); log(pathArray); }; created pathArray for each random map now looks like this for a small random map... (in part, not posting the entire array) ....{"left":420,"top":420,"rotation":180,"path":"[[840,735],[805,735],[805,805],[735,805],[735,840]]"}, {"left":420,"top":420,"rotation":180,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":420,"rotation":180,"path":"[[0,315],[35,315],[35,385],[385,385],[385,35],[315,35],[315,0]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[840,735],[805,735],[805,805],[735,805],[735,840]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[315,840],[315,805],[385,805],[385,315]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,735],[35,735],[35,805],[105,805],[105,840]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,525],[35,525],[35,315]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":1260,"rotation":180,"path":"[[0,315],[35,315],[385,315],[385,35],[315,35],[315,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[805,420],[400,805]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[315,0],[315,35],[525,35],[525,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[840,105],[805,105],[805,35],[735,35],[735,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[0,105],[35,105],[35,35],[105,35],[105,0]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[0,315],[35,315],[35,525],[0,525]]"}, {"left":420,"top":2100,"rotation":-90,"path":"[[840,315],[805,315],[805,525],[840,525]]"}.... I just edited my last post with a ton of bug fixes (like I forgot that if I edit the array I change the main one as well :P).
1392666532
Alex L.
Pro
Sheet Author
Stephen S. said: Here is the current code... I will delete this later so its only at the top: Getting an error: Error: Firebase.set failed: First argument contains NaN in property 'width' Your paths shouldnt be strings this: {tileName: "Geo_Type_A_0001", path:"[[0,105],[105,105],[105,0]]]"}, should be: {tileName: "Geo_Type_A_0001", path:[[0,105],[105,105],[105,0]]]},
1392666633
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Alex, Posted what I currently have above.... getting an error (going to remove that post later... just the fastest way to share the code.) I am expecting to send to your functions one path at time with offset and rotation from the pathArray and and you place them on the map layer as they should be based on rotation. Is that correct?
1392666684
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Alex L. said: Stephen S. said: Here is the current code... I will delete this later so its only at the top: Getting an error: Error: Firebase.set failed: First argument contains NaN in property 'width' Your paths shouldnt be strings this: {tileName: "Geo_Type_A_0001", path:"[[0,105],[105,105],[105,0]]]"}, should be: {tileName: "Geo_Type_A_0001", path:[[0,105],[105,105],[105,0]]]}, GOT IT!
1392667355
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Fixed the string issue a few posts up...... ALEX!!!!!!! You got me SOOOO CLOSE! 420px to the right and 420px down.... PLEASE PLEASE where do I fix it!!!!!!!!!!!!!!!!
1392667872

Edited 1392668245
Alex L.
Pro
Sheet Author
Stephen S. said: Fixed the string issue a few posts up...... ALEX!!!!!!! You got me SOOOO CLOSE! 420px to the right and 420px down.... PLEASE PLEASE where do I fix it!!!!!!!!!!!!!!!! the pos you are using is the mid of the picture - 420 off it. createPath(givenPath, givenAngle, givenX-420, givenY-420);
1392669145
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Yes... the paths were are determined in relation to the center of the tile. _.each(pathArray, function(pathArrayEach) { var givenPath = pathArrayEach.path; var givenAngle = pathArrayEach.rotation; var givenX = pathArrayEach.left - 420; var givenY = pathArrayEach.top - 420; /* ------------------- createPath function was most helpfully provided by Alex L. https://app.roll20.net/users/71687/alex-l ------------------- */ createPath(givenPath, givenAngle, givenX, givenY); }); A) Is not turned correctly (when I build the tile i read what is on the map) B) Some of these lines where from when I was trying to make paths that where 840px by 840px .... so the outliers can be ignored. C) Is spot on and basically the same tile as B D) is spot on... Something is a bit off..... but Mr. Bulb is interacting with the dynamic lighting as expected.
1392671028
Alex L.
Pro
Sheet Author
Corrected function: function createPath(inputPath, angle, Xoffset, Yoffset) { var PathArray = []; // use a god dam copy you n00b :P if(!angle) angle = 0; if(!Xoffset) Xoffset = 0; if(!Yoffset) Yoffset = 0; //use these to work our how big the path is. var maxX = 0; var minX = false; var maxY = 0; var minY = false; //find the min and max X and Y. Rotate the cords in the array. for(var i = 0; i < inputPath.length; i++) { PathArray.push([inputPath[i][0], inputPath[i][1]]); PathArray[i] = rot(angle, PathArray[i]); if(PathArray[i][0] > maxX) maxX = PathArray[i][0]; if(minX === false || Number(PathArray[i][0]) < Number(minX)) minX = PathArray[i][0]; if(PathArray[i][1] > maxY) maxY = PathArray[i][1]; if(minY === false || PathArray[i][1] < minY) minY = PathArray[i][1]; } //work out the size and position the object within the 12^2 area. var objectWidth = maxX - minX; var objectHeight = maxY - minY; var objectTop = minY + (objectHeight/2); var objectLeft = minX + (objectWidth/2); //fix array to remove positioning. for(var i = 0; i < PathArray.length; i++) { PathArray[i][0] = PathArray[i][0] - objectLeft + (objectWidth/2); PathArray[i][1] = PathArray[i][1] - objectTop + (objectHeight/2); } //Convert the array to a string. var pathString = ""; for(var i = 0; i < PathArray.length; i++) { if(i != 0) { pathString += ",[\"L\"," + PathArray[i][0] + "," + PathArray[i][1] + "]"; } else { pathString = "[\[\"M\"," + PathArray[i][0] + "," + PathArray[i][1] + "]"; } } pathString += "\]"; objectTop = objectTop + Yoffset; //offset should be the relative position from the top left in multiples of 840. objectLeft = objectLeft + Xoffset; createObj("path",{ layer: "walls", _path: pathString, width: objectWidth, height: objectHeight, top: objectTop, left: objectLeft, rotation: 0, stroke: "#00ff00", pageid: Campaign().get("playerpageid") }); //You may need to change the page id. }
1392672170
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
OMG OMG OMG
1392673221

Edited 1392674609
VICTORY!! Does this mean we have a finished code? :D
1392675408

Edited 1392675617
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Thanks to Alex it is functionally solved and I updated the lead post. Some minor tweaks are needed (for example ensure when a tile side is chosen and the tile is rotated the lighting can track it all down.) Also want something that improve setting up the tiles and stepping through to ensuring it is easy to setup (auto setup of macros and see if I can get token actions to aid setting up the map... the rotation "arm" is hard to grab for example.) Also going to post the shadow drops and "off map" image so it will be easy for creators to make tile packs that work with this pack. Doors that swing at the hinge would also be nice. But yea... the code works as is. A "two" click 96 by 96 map below.... talk about a time saver!!
This is so awesome.. I'm really excited! Can't wait to get it going for myself :)
1392744881
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
https://app.roll20.net/forum/post/655402/script-ra... Updated the SCRIPT with improved features and more information (link will take you to the top of the thread.)
1392754256

Edited 1392755550
Flawless. You sir, deserve an award for this. (and you kept it under 1,000 lines too!) EDIT: The rotation doesn't seem to be working for me, unfortunately. (and the light generation doesn't work if I change the tiles for some reason).. other than that it works great! I'm trying to remember how you said to exclude tiles from the generation.. You did mention it, didn't you?
1392773608
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
So... I notice something glitchy with that. Unfortunately I am traveling and will not be able to dig into it for a few days. But I think the lighting script needs one of the arrays rebuilt for it for a till change (it only "knows" what they generator choose) or I blundered something. To block a tile you need set the "block" value to true in the tile information array.
1392773804
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
You know... Maps could be stored as an output to a log of some sort and people could share maps by just sharing the array!!!!!!
I'll have to go through and take a look at the block value in the script. I think it could be fun to play around with just the hall-like tiles (no open rooms) or just the cavernous tiles. :) dont net worry too much about having to dig into the glitches. That's all just fine tuning. You got the most important parts done and if something isn't perfectly suited to what I want, I can just re-!geo it lol.
1392813017
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Depending on what the business center PC are like in the hotels (I have to go to several places) I maybe able to work on it (I really want to get this right :P because I am hoping other content creators will make tiles.) I just am not going to work on my Ipad because I am old and can't see :P. In the notes section of the lead post I touch on the "blocking" and unblocking tiles: Geo_Type_A_0031 and Geo_Type_A_0032 are used to "fill in" the offset area. "Blocked" value turns off tiles that should not be randomly placed. var geomorphicTilesInformation = [ {tileName: "Geo_Type_A_0031", edge: false, corner: false, entrance: false, type: "d", rotation: 0, rarity: 100, blocked: true }, {tileName: "Geo_Type_A_0032", edge: false, corner: false, entrance: false, type: "d", rotation: 0, rarity: 100, blocked: true },