Closed ggagnon76 closed 3 years ago
This is something I've been thinking about actually, I just haven't had an actual reason to do it. I'll give you a ping on Discord when I have the opportunity.
You can call SceneTiler.createTile(source, uuid, x, y)
where source is a Scene, and that should create the tile. You don't get much control over the process, but calling this directly should work just as well as drag & dropping does.
uuid is the id of the source scene?
And SceneTiler.createTile() is available in global scope?
It is available in global scope, yes. UUIDs are not just the ID of the document, they are a bit more complicated. See the dropCanvasData
method for how I construct the UUID (these are a Foundry core concept, and are nessesary for locating scenes stored in compendiums).
Also, once you create the tile, if you programmatically update it to be locked, that should trigger the rest of the deployment.
I kind of see. I'm a hobbyist at this, so not able to follow completely at first glance. Here's how I'm reading this: If I store my scenes in a compendium (not in the scenes folder), I can incorporate them directly by creating 'source' from the UUID, then feeding source, UUID and x/y to your createTile() method. No need for the scene to ever be in the scene folder. Is that correct?
Hey @ggagnon76 I wanted to add my "vote" to this request as well. I'm also pondering the idea of "generated" dungeon.
My approach has been to use the awesome DungeonMorph maps (from Inkwell Ideas), which I've already extracted from the PDF I bought some time ago. I created rotated versions of every map (base 90 180 270 degrees), as well as mirrored version of the map. so I have some 800+ scenes that bulk imported.
I've then created a small randomizer (using roll tables) to randomize the selection of which map should be presented, and it shows that to the GM only.
The problem is I don't know how to "automagically" put the tile onto the scene (without dragging), which is why I came here.
So @zeel01 , perhaps we can consider this my vote for this. I am a developer by profession, but this Foundry VTT system (and java) are well outside my wheelhouse.
I will try to use the prior comments in this thread to try and make this work in my context. (my scenes are just jammed into a folder inside of the campaign, but themselves will be sourced from a compendium when I'm ready)
This is what I have at this point. I'll break the code up into parts, even though it's all one macro...
console.log ("====start====")
const Side = await game.tables.entities.find(t => t.name === "DungeonMorph_Side");
const Deck = await game.tables.entities.find(t => t.name === "DungeonMorph_Deck");
const Orientation = await game.tables.entities.find(t => t.name === "DungeonMorph_Orientation");
const Mode = await game.tables.entities.find(t => t.name === "DungeonMorph_Mode");
SideResults = await Side.roll()
DeckResults = await Deck.roll()
OrientationResults = await Orientation.roll()
ModeResults = await Mode.roll()
//console.log (SideResults)
//console.log (DeckResults)
//console.log (OrientationResults)
//console.log (ModeResults)
//console.log (SideResults.results[0].data.text)
//console.log (DeckResults.results[0].data.text)
//console.log (OrientationResults.results[0].data.text)
//console.log (ModeResults.results[0].data.text)
MapTile = SideResults.results[0].data.text +
DeckResults.results[0].data.text +
"_" +
OrientationResults.results[0].data.text +
"_" +
ModeResults.results[0].data.text
console.log (MapTile)
At this point, I have the name of the "scene" I want to use as a tile in the variable MapTile
but when I try to load the scene as a tile ... nothing happens.
And all subsequent attemptws to use the the macro fail until I reload the browser.
Scene = game.scenes.find(t => t.name === MapTile)
console.log (Scene)
SceneTiler.createTile(Scene, Scene.uuid, 5000,5000)
console.log ("=====end=====")
after taking a look at dropCanvasData, I was able to get this working.
const Side = await game.tables.entities.find(t => t.name === "DungeonMorph_Side");
const Deck = await game.tables.entities.find(t => t.name === "DungeonMorph_Deck");
const Orientation = await game.tables.entities.find(t => t.name === "DungeonMorph_Orientation");
const Mode = await game.tables.entities.find(t => t.name === "DungeonMorph_Mode");
SideResults = await Side.roll()
DeckResults = await Deck.roll()
OrientationResults = await Orientation.roll()
ModeResults = await Mode.roll()
MapTile = SideResults.results[0].data.text +
DeckResults.results[0].data.text +
"_" +
OrientationResults.results[0].data.text +
"_" +
ModeResults.results[0].data.text
console.log (MapTile)
Up to this point, all this was about was "generating" the scene name we want to turn into a tile, and store it in the MapTile Variable
const SceneTile = await game.scenes.find(t => t.name === MapTile)
const source = await fromUuid(SceneTile.uuid)
const SceneUuid = SceneTile.uuid
const LocalPosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(canvas.stage)
//SceneTiler is going to want to place the "middle" of the Scene as a token at the cursor.
//We need to adjust that...
x = LocalPosition.x + (SceneTile.dimensions.sceneHeight / 2)
y = LocalPosition.y + (SceneTile.dimensions.sceneWidth / 2)
//Now we need to locate the top left corner of the "target grid square"
const LocalGridSize = canvas.scene.dimensions.size;
x = Math.floor(x / LocalGridSize ) * LocalGridSize
y = Math.floor(y / LocalGridSize ) * LocalGridSize
SceneTiler.createTile(source, SceneUuid, x, y)
The only thing left to figure out, is how to "Lock" the tile to pull forward all of the other properties (like walls and stuff), which I've not quite setup yet...
The module I'm in the process of creating (very slowly) is probably fits your use case. Unfortunately my free time is scarce and my progress is slow.
As for your request to Zeel, all the functions in Scene Tiler are already available globally. I was able to generate a scene as a tile from a compendium scene and successfully deploy it into my empty scene. NOTE that for Zeel's Scene Tiler to work, the scene has to be in a compendium.
I would hate to duplicate work, but I wouldn't want to inflict my development pace on any one else. You can look at my code and take what you need to get your implementation working.
https://github.com/ggagnon76/scene-zoetrope/blob/master/scripts/zoetrope.js
If you have any questions about the code and why I did things the way I did, you can open an issue in my repo and I will respond there, as it would be out of scope in this thread.
Oh, I also meant to point out that Zeel's Scene Tiler allows for the scene/tile to be rotated. So all your duplicate images with different orientations are not necessary.
Thanks for the tip about rotation... I figured out how to do that and now my script looks like this...
All I need to now is figure out how to lock the tile to bring forward the related elements like walls and stuff...
const Side = await game.tables.entities.find(t => t.name === "DungeonMorph_Side");
const Deck = await game.tables.entities.find(t => t.name === "DungeonMorph_Deck");
const Orientation = await game.tables.entities.find(t => t.name === "DungeonMorph_Orientation");
const Mode = await game.tables.entities.find(t => t.name === "DungeonMorph_Mode");
SideResults = await Side.roll()
DeckResults = await Deck.roll()
OrientationResults = await Orientation.roll()
ModeResults = await Mode.roll()
MapTile = SideResults.results[0].data.text +
DeckResults.results[0].data.text +
"_" +
"000" +
"_" +
ModeResults.results[0].data.text
console.log (MapTile)
const SceneTile = await game.scenes.find(t => t.name === MapTile)
const source = await fromUuid(SceneTile.uuid)
const SceneUuid = SceneTile.uuid
const LocalPosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(canvas.stage)
//SceneTiler is going to want to place the "middle" of the Scene as a token at the cursor.
//We need to adjust that...
x = LocalPosition.x + (SceneTile.dimensions.sceneHeight / 2)
y = LocalPosition.y + (SceneTile.dimensions.sceneWidth / 2)
//Now we need to locate the top left corner of the "target grid square"
const LocalGridSize = canvas.scene.dimensions.size;
x = Math.floor(x / LocalGridSize ) * LocalGridSize
y = Math.floor(y / LocalGridSize ) * LocalGridSize
//Locate the tile we just created on the canvas, and rotate it...
NewTile = await SceneTiler.createTile(source, SceneUuid, x, y)
CanvasTile = canvas.scene.tiles.find(t => t.id === NewTile[0]._id)
await CanvasTile.update({rotation: parseInt(OrientationResults.results[0].data.text) })
I didn't lock it, since I want to be able to translate everything programmatically as necessary.
I used this part of Zeel's code:
SceneTiler.deploySceneTile(myTile[0].data);
You'll have to replace 'myTile[0].data' above with your equivalent. Should be enough to get you going.
You can lock the tile by updating it like:
await tile.update({ locked: true });
This is essentially exactly what happens when you click the lock button from the GUI.
Really cool stuff you guys have been doing, it may be useful to have an ongoing conversation regarding this on Discord. Feel free to give me a ping (zeel#4200) in the League of Foundry Devs Discord: https://discord.gg/feRvbhVnvf
I'm especially interested in any suggestions for how I could make using the the module's API better for integrations. I think all the right pieces are there, but I might be able to make working with them a bit simpler.
I think this is complete?
More a request than an issue:
I am brainstorming my next module, which will be a randomly generated labyrinth made up of tiles. At first I thought of using Token Attacher to have a 'prefab' with background (the tile), walls, lights, sounds, tokens, etc..
Upon reflection, I am inclined to think that Scene Tiler might work better, especially if I want to make modifications to individual scenes during development. Also because of what I want to do with stuff in the flags of the scene.
My request would be an API (?) in Scene Tiler where I could generate a tile via a function I could call in my module. I would also need the flags from the scene to be copied to the flags on the tile.
Is this too much of an ask? If you want to discuss, I can be reached in the league discord via: Kerrec Snowmane#5264
Thanks!