diff --git a/README.md b/README.md index d70db3c..7157911 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ This is still in very early stages still. Some ideas for the future of the mod i * Impassable tiles and/or "dangerous" tiles. # Changelog +1.0.8 - Fixing some bugs, adding Copy & Paste functionality, adding code to keep player updated. 1.0.7 - Changing terrain to drawable rather than squares, adding terrain type and environment properties 1.0.6 - Adding option to set cost of measured template, and track difficult terrain of other tokens 1.0.5 - Fixing issue where I didn't use a isGM when I should have diff --git a/classes/terrainlayer.js b/classes/terrainlayer.js index d46b05f..cb3e31a 100644 --- a/classes/terrainlayer.js +++ b/classes/terrainlayer.js @@ -218,14 +218,14 @@ export class TerrainLayer extends PlaceablesLayer { } async toggle(show, emit = false) { - //this.highlight.children[0].visible = !this.highlight.children[0].visible; if (show == undefined) show = !this.showterrain; this.showterrain = show; - game.settings.set("TerrainLayer", "showterrain", this.showterrain); - if (game.user.isGM && emit) { - //await canvas.scene.setFlag('TerrainLayer','sceneVisibility', this.highlight.children[0].visible ) - game.socket.emit('module.TerrainLayer', { action: 'toggle', arguments: [this.showterrain] }) + canvas.terrain.visible = this.showterrain; + if (game.user.isGM) { + game.settings.set("TerrainLayer", "showterrain", this.showterrain); + if (emit) + game.socket.emit('module.TerrainLayer', { action: 'toggle', arguments: [this.showterrain] }) } } @@ -280,14 +280,22 @@ export class TerrainLayer extends PlaceablesLayer { this._costGrid = null; canvas.scene.update(flags).then(() => { - for (let update of updates) { - let terrain = this.placeables.find(t => { return t.id == update._id }); - if (terrain != undefined) - terrain.update(update, { save: false }); - } + this.updateTerrain(updates); }); } + updateTerrain(data, options) { + data = data instanceof Array ? data : [data]; + for (let update of data) { + let terrain = this.placeables.find(t => { return t.id == update._id }); + if (terrain != undefined) + terrain.update(update, { save: false }); + } + if (game.user.isGM) { + game.socket.emit('module.TerrainLayer', { action: 'updateTerrain', arguments: [data]}); + } + } + async deleteMany(ids, options = {}) { //+++ need to update this to only respond to actual deletions @@ -305,6 +313,9 @@ export class TerrainLayer extends PlaceablesLayer { canvas.scene.data.terrain.findSplice(t => { return t._id == id; }); let key = `flags.TerrainLayer.-=terrain${id}`; updates[key] = null; + + if (game.user.isGM) + game.socket.emit('module.TerrainLayer', { action: 'deleteTerrain', arguments: [id] }); } if (!options.isUndo) @@ -333,7 +344,7 @@ export class TerrainLayer extends PlaceablesLayer { const { preview, createState, originalEvent } = event.data; // Continue polygon point placement - if (createState >= 1) { + if (createState >= 1 && preview instanceof Terrain) { let point = event.data.destination; if (!originalEvent.shiftKey) point = canvas.grid.getSnappedPosition(point.x, point.y, this.gridPrecision); preview._addPoint(point, false); @@ -368,6 +379,7 @@ export class TerrainLayer extends PlaceablesLayer { super._onDragLeftStart(event); const data = this._getNewTerrainData(event.data.origin); const terrain = new Terrain(data); + event.data.preview = this.preview.addChild(terrain); terrain.draw(); } @@ -413,6 +425,9 @@ export class TerrainLayer extends PlaceablesLayer { preview._chain = false; preview.constructor.create(createData).then(d => { d._creating = true; + if (game.user.isGM) { + game.socket.emit('module.TerrainLayer', { action: 'createTerrain', arguments: [createData] }); + } }); } @@ -470,6 +485,51 @@ export class TerrainLayer extends PlaceablesLayer { event.data.coords = coords; }*/ + pasteObjects(position, { hidden = false, snap = true } = {}) { + if (!this._copy.length) return []; + + // Adjust the pasted position for half a grid space + if (snap) { + position.x -= canvas.dimensions.size / 2; + position.y -= canvas.dimensions.size / 2; + } + + // Get the left-most object in the set + this._copy.sort((a, b) => a.data.x - b.data.x); + let { x, y } = this._copy[0].data; + + // Iterate over objects + const toCreate = []; + for (let c of this._copy) { + let data = duplicate(c.data); + let dest = { x: position.x + (data.x - x), y: position.y + (data.y - y) }; + if (snap) dest = canvas.grid.getSnappedPosition(dest.x, dest.y); + delete data._id; + toCreate.push(Terrain.normalizeShape(mergeObject(data, { + x: dest.x, + y: dest.y, + hidden: data.hidden || hidden + }))); + } + + // Call paste hooks + Hooks.call(`pasteTerrain`, this._copy, toCreate); + + // Create the object + let created = toCreate.map((data) => { + return Terrain.create(data).then(d => { + d._creating = true; + if (game.user.isGM) { + game.socket.emit('module.TerrainLayer', { action: 'createTerrain', arguments: [data] }); + } + }); + }); + + ui.notifications.info(`Pasted data for ${toCreate.length} Terrain objects.`); + created = created instanceof Array ? created : [created]; + return created.map(c => this.get(c._id)); + } + /* selectObjects({ x, y, width, height, releaseOptions = {}, controlOptions = {} } = {}) { const oldSet = Object.values(this._controlled); @@ -515,4 +575,21 @@ export class TerrainLayer extends PlaceablesLayer { terrainExists(pxX, pxY) { return canvas.scene.data.terrain.find(t => { return t.x == pxX && t.y == pxY }) != undefined; }*/ + + + //This is used for players, to add an remove on the fly + createTerrain(data, options = {}) { + let userId = game.user._id; + let object = canvas.terrain.createObject(data); + object._onCreate(options, userId); + canvas.scene.data.terrain.push(data); + } + + deleteTerrain(id, options = {}) { + const object = this.get(id); + this.objects.removeChild(object); + object._onDelete(options, game.user.id); + object.destroy({ children: true }); + canvas.scene.data.terrain.findSplice(t => { return t._id == id; }); + } } \ No newline at end of file diff --git a/img/0.5x.svg b/img/0.5x.svg index 275b977..6d6625a 100644 --- a/img/0.5x.svg +++ b/img/0.5x.svg @@ -1,5 +1,5 @@ - + diff --git a/img/2x.svg b/img/2x.svg index 966eade..bd75dc1 100644 --- a/img/2x.svg +++ b/img/2x.svg @@ -1,5 +1,5 @@ - + diff --git a/img/3x.svg b/img/3x.svg index 9ff03ea..d671aef 100644 --- a/img/3x.svg +++ b/img/3x.svg @@ -1,5 +1,5 @@ - + diff --git a/img/4x.svg b/img/4x.svg index 2e22e9f..3e9725f 100644 --- a/img/4x.svg +++ b/img/4x.svg @@ -1,8 +1,8 @@ - + - + diff --git a/module.json b/module.json index 209a886..6a555a1 100644 --- a/module.json +++ b/module.json @@ -3,7 +3,7 @@ "title": "Terrain Layer", "description": "A base module that adds a Terrain Layer to Foundry to paint difficult terrain squares and to be used as a dependency for other mods who might integrate it with their functionality.", "authors": [{"name":"Will Saunders","email":"willsaunders1014@gmail.com" }, {"name":"IronMonk, ironmonk88#4075" }], - "version": "1.0.7", + "version": "1.0.8", "minimumCoreVersion": "0.6.6", "compatibleCoreVersion":"0.7.9", "scripts":[ @@ -36,6 +36,6 @@ "socket":true, "url":"https://github.com/ironmonk88/TerrainLayer", "changelog":"https://raw.githubusercontent.com/ironmonk88/TerrainLayer/main/README.md", - "download": "https://github.com/ironmonk88/TerrainLayer/archive/1.0.7.zip", + "download": "https://github.com/ironmonk88/TerrainLayer/archive/1.0.8.zip", "manifest": "https://github.com/ironmonk88/TerrainLayer/releases/latest/download/module.json" } diff --git a/terrain-main.js b/terrain-main.js index 244664a..d2d51b1 100644 --- a/terrain-main.js +++ b/terrain-main.js @@ -27,7 +27,8 @@ async function checkUpgrade() { let gW = scene.data.grid; let gH = scene.data.grid; - for (let [k, v] of Object.entries(scene.data.flags?.TerrainLayer)) { + let data = duplicate(scene.data.flags?.TerrainLayer); + for (let [k, v] of Object.entries(data)) { if (k.startsWith('terrain')) { if (k == 'terrainundefined' || v == undefined || v.x == undefined || v.y == undefined) await scene.unsetFlag('TerrainLayer', k); @@ -45,7 +46,7 @@ async function checkUpgrade() { let grid = scene.getFlag('TerrainLayer', 'costGrid'); for (let y in grid) { for (let x in grid[y]) { - if (Object.values(scene.data.flags.TerrainLayer).find(t => { return t.x == (parseInt(x) * gW) && t.y == (parseInt(y) * gH); }) == undefined) { + if (Object.values(data).find(t => { return t.x == (parseInt(x) * gW) && t.y == (parseInt(y) * gH); }) == undefined) { inform(); let id = makeid(); let data = { _id: id, x: parseInt(x) * gW, y: parseInt(y) * gH, points: [[0, 0], [gW, 0], [gW, gH], [0, gH], [0, 0]], width: gW, height: gH, multiple: grid[y][x].multiple }; @@ -53,6 +54,7 @@ async function checkUpgrade() { } } } + await scene.unsetFlag('TerrainLayer', 'costGrid'); } }; } @@ -83,7 +85,7 @@ Hooks.on('ready', () => { Hooks.on('init', () => { game.socket.on('module.TerrainLayer', async (data) => { - console.log(data) + console.log(data); canvas.terrain[data.action].apply(canvas.terrain, data.arguments); }); @@ -106,11 +108,14 @@ Hooks.on('init', () => { let oldOnDragLeftCancel = Token.prototype._onDragLeftCancel; Token.prototype._onDragLeftCancel = function (event) { //event.stopPropagation(); - if (canvas != null) + const ruler = canvas.controls.ruler; + + if (canvas != null && !(ruler.isDragRuler || ruler._state === Ruler.STATES.MEASURING)) canvas.terrain.visible = (canvas.grid.type != 0 && (canvas.terrain.showterrain || ui.controls.activeControl == 'terrain')); oldOnDragLeftCancel.apply(this, [event]) } + //let handleDragCancel = MouseInteractionManager.prototype._handleDragCancel; /*