From 60286580cdb384a30b426475396e4afe34ff11b1 Mon Sep 17 00:00:00 2001 From: ironmonk88 <75920956+ironmonk88@users.noreply.github.com> Date: Sun, 9 Oct 2022 14:30:06 -0700 Subject: [PATCH] 10.4 changes --- CHANGELOG.md | 14 ++++++ classes/terraindocument.js | 2 + classes/terrainlayer.js | 91 ++++++++++++++++++++------------------ classes/terrainshape.js | 13 +++--- js/controls.js | 4 +- js/settings.js | 17 +++++-- module.json | 4 +- 7 files changed, 87 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4e68e9..30f9c6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# Version 10.4 + +Fixed issue when restoring a Terrain after it's been deleted when using Ctrl-Z. + +Fixed issue finding data when the Measured Template has no flags set. + +Addeed the option to set if you only want hostile creatures to cause difficult terrain. + +Updated the API for calculating terrain cost. + +Fixed issue with drawing shapes towards the upper left. + +Fixed issue getting the correct shape data. + # Version 10.3 Fixed a spelling mistake in one of my fixes. diff --git a/classes/terraindocument.js b/classes/terraindocument.js index d933040..e634720 100644 --- a/classes/terraindocument.js +++ b/classes/terraindocument.js @@ -208,6 +208,8 @@ export class TerrainDocument extends CanvasDocumentMixin(BaseTerrain) { let originals = []; let created = []; for (let terrain of data) { + if (terrain instanceof TerrainDocument) + terrain = terrain.toObject(); //update this object // mergeObject(terrainDoc.data, data); terrain._id = terrain._id || makeid(); diff --git a/classes/terrainlayer.js b/classes/terrainlayer.js index 5396325..0198503 100644 --- a/classes/terrainlayer.js +++ b/classes/terrainlayer.js @@ -6,7 +6,7 @@ import { PolygonTerrainInfo, TemplateTerrainInfo, TokenTerrainInfo } from './ter import { makeid, log, debug, warn, error, i18n, setting, getflag } from '../terrain-main.js'; import EmbeddedCollection from "../../../common/abstract/embedded-collection.mjs"; -export let environments = key => { +export let environments = (key) => { return canvas.terrain.getEnvironments(); }; @@ -174,7 +174,7 @@ export class TerrainLayer extends PlaceablesLayer { continue; if (options.ignore?.includes(terrain.document.environment)) continue; - let reducers = options.reduce?.filter(e => e.id == terrain.document.environment || (useObstacles && e.id == terrain.document.obstacle)); + let reducers = options.reduce?.filter((e) => e.id == terrain.document.environment || (useObstacles && e.id == terrain.document.obstacle)); terrainInfos.push(new PolygonTerrainInfo(terrain, reducers)); } return terrainInfos; @@ -186,7 +186,7 @@ export class TerrainLayer extends PlaceablesLayer { const terrainInfos = options.list || []; for (const template of canvas.templates.placeables) { - const terrainFlag = template.flags['enhanced-terrain-layer']; + const terrainFlag = getProperty(template, "flags.enhanced-terrain-layer"); if (!terrainFlag) continue; const terraincost = terrainFlag.multiple ?? 1; @@ -200,7 +200,7 @@ export class TerrainLayer extends PlaceablesLayer { continue; if (options.ignore?.includes(environment)) continue; - let reducers = options.reduce?.filter(e => e.id == environment || (useObstacles && e.id == obstacle)); + let reducers = options.reduce?.filter((e) => e.id == environment || (useObstacles && e.id == obstacle)); terrainInfos.push(new TemplateTerrainInfo(template, reducers)); } return terrainInfos; @@ -212,11 +212,14 @@ export class TerrainLayer extends PlaceablesLayer { let isDead = options.isDead || function (token) { return !!token.actor?.effects?.find(e => { const core = e.flags["core"]; - return core && core["statusId"] === CONFIG.specialStatusEffects.DEFEATED; + return (core && core["statusId"] === CONFIG.specialStatusEffects.DEFEATED); }); } - if ((setting("tokens-cause-difficult") || setting("dead-cause-difficult")) && canvas.grid.type != CONST.GRID_TYPES.GRIDLESS && !options.ignore?.includes("tokens")) { + let tokenDifficult = setting("tokens-cause-difficult"); + let tokenDead = setting("dead-cause-difficult"); + + if ((tokenDifficult != "false" || tokenDead != "false") && canvas.grid.type != CONST.GRID_TYPES.GRIDLESS && !options.ignore?.includes("tokens")) { const elevation = this.calcElevationFromOptions(options); const tokenId = options.tokenId || options?.token?.id; for (const token of canvas.tokens.placeables) { @@ -224,10 +227,13 @@ export class TerrainLayer extends PlaceablesLayer { continue; if (token.hidden) continue; - if (elevation != undefined && token.elevation != elevation) + if (elevation != undefined && token.elevation != undefined && token.elevation != elevation) continue; let dead = isDead(token); - if ((setting("dead-cause-difficult") && dead) || (setting("tokens-cause-difficult") && !dead)) { + let checkValue = dead ? tokenDead : tokenDifficult; + if (checkValue == 'true' || + (token.document.disposition == CONST.TOKEN_DISPOSITIONS.FRIENDLY && checkValue == "friendly") || + (token.document.disposition != CONST.TOKEN_DISPOSITIONS.FRIENDLY && checkValue == "hostile")) { let reducers = options.reduce?.filter(e => e.id == 'token') terrainInfos.push(new TokenTerrainInfo(token, reducers)); } @@ -241,12 +247,7 @@ export class TerrainLayer extends PlaceablesLayer { return this.listTokenTerrain({ list: this.listMeasuredTerrain({ list: this.listTerrain(options), ...options }), ...options }) } - costWithTerrain(pts, terrain, options = {}) { - pts = pts instanceof Array ? pts : [pts]; - - const hx = (canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? 0 : canvas.dimensions.size / 2); - const hy = (canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? 0 : canvas.dimensions.size / 2); - + calculateCombinedCost(terrain, options = {}) { let calculate = options.calculate || 'maximum'; let calculateFn; if (typeof calculate == 'function') @@ -262,42 +263,37 @@ export class TerrainLayer extends PlaceablesLayer { } } - const details = []; - let total = 0; - for (const pt of pts) { - let cost = null; - const [gx, gy] = (canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? [pt.x, pt.y] : canvas.grid.grid.getPixelsFromGridPosition(pt.y, pt.x)); + let total = null; + for (const terrainInfo of terrain) { + if (typeof calculateFn == 'function') + total = calculateFn(terrainInfo.cost, total, terrainInfo.object); + } + return total ?? 1; + } - const tx = (gx + hx); - const ty = (gy + hy); + costWithTerrain(pts, terrain, options = {}) { + const multipleResults = pts instanceof Array; + pts = multipleResults ? pts : [pts]; - for (const terrainInfo of terrain) { - const testX = tx - terrainInfo.object.document.x; - const testY = ty - terrainInfo.object.document.y; + const hx = (canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? 0 : canvas.dimensions.size / 2); + const hy = (canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? 0 : canvas.dimensions.size / 2); - if (!terrainInfo.shape.contains(testX, testY)) - continue; + const costs = []; + for (const pt of pts) { + const [gx, gy] = canvas.grid.type == CONST.GRID_TYPES.GRIDLESS || options.ignoreGrid === true ? [pt.x, pt.y] : canvas.grid.grid.getPixelsFromGridPosition(pt.y, pt.x); - const terraincost = terrainInfo.cost; - if (typeof calculateFn == 'function') - cost = calculateFn(terraincost, cost, terrainInfo.object); - - const detail = { - cost: terrainInfo.rawCost, - object: terrainInfo.object, - reduce: terrainInfo.reducers, - total: cost, - }; - details.push(detail); - } + const tx = gx + hx; + const ty = gy + hy; - total += (cost != undefined ? cost : 1); + terrain = terrain.filter((t) => + t.shape.contains(tx - t.object.x, ty - t.object.y) + ); + const cost = this.calculateCombinedCost(terrain, options); + costs.push(cost); } - if (options.verbose === true) - return { cost: total, details: details, calculate: calculate }; - else - return total; + if (multipleResults) return costs; + else return costs[0]; } cost(pts, options = {}) { @@ -320,6 +316,13 @@ export class TerrainLayer extends PlaceablesLayer { return t.shape.contains(testX, testY); }); + const elevation = this.calcElevationFromOptions(options); + if (elevation !== null) { + terrains = terrains.filter( + (t) => (elevation) => t.bottom && elevation <= t.top + ); + } + return terrains; } @@ -571,7 +574,7 @@ export class TerrainLayer extends PlaceablesLayer { // Successful drawing completion if (createState === 2) { - const distance = Math.hypot(destination.x - preview.x, destination.y - preview.y); + const distance = Math.hypot(preview.shape.width, preview.shape.height); const minDistance = distance >= (canvas.dimensions.size / this.gridPrecision); const completePolygon = preview.isPolygon && (preview.document.shape.points.length > 4); diff --git a/classes/terrainshape.js b/classes/terrainshape.js index aed2729..f69a851 100644 --- a/classes/terrainshape.js +++ b/classes/terrainshape.js @@ -53,19 +53,20 @@ export class TerrainShape extends DrawingShape { } get _pixishape() { - let shape; - switch (this.document.shape.type) { + let { x, y, width, height, shape } = this.document; + let result; + switch (shape.type) { case Drawing.SHAPE_TYPES.RECTANGLE: - shape = new PIXI.Rectangle(this.x, this.y, this.width, this.height); + result = new PIXI.Rectangle(0, 0, width, height); break; case Drawing.SHAPE_TYPES.ELLIPSE: - shape = new PIXI.Ellipse(this.x, this.y, this.width / 2, this.height / 2); + result = new PIXI.Ellipse(width / 2, height / 2, Math.max(Math.abs(width / 2), 0), Math.max(Math.abs(height / 2), 0)); break; case Drawing.SHAPE_TYPES.POLYGON: - shape = new PIXI.Polygon(this.document.shape.points); + result = new PIXI.Polygon(shape.points); break; } - return shape; + return result; } contains(x, y) { diff --git a/js/controls.js b/js/controls.js index e3967ce..9a4eeca 100644 --- a/js/controls.js +++ b/js/controls.js @@ -21,12 +21,12 @@ Hooks.on('getSceneControlButtons', (controls) => { { name: "rect", title: "CONTROLS.DrawingRect", - icon: "fa-solid fa-square" + icon: "fa-regular fa-square" }, { name: "ellipse", title: "CONTROLS.DrawingEllipse", - icon: "fa-solid fa-circle" + icon: "fa-regular fa-circle" }, { name: "polygon", diff --git a/js/settings.js b/js/settings.js index 6720a1c..2ebf271 100644 --- a/js/settings.js +++ b/js/settings.js @@ -16,6 +16,13 @@ export const registerSettings = function () { 'clear': 'Clear' }; + let tokenoptions = { + 'false': 'None', + 'friendly': 'Friendly', + 'hostile': 'Hostile', + 'true': 'Any' + }; + game.settings.registerMenu(modulename, 'edit-colors', { name: 'Edit Colors', label: 'Edit Colors', @@ -100,16 +107,18 @@ export const registerSettings = function () { hint: "EnhancedTerrainLayer.tokens-cause-difficult.hint", scope: "world", config: true, - default: false, - type: Boolean + choices: tokenoptions, + default: "false", + type: String }); game.settings.register(modulename, 'dead-cause-difficult', { name: "EnhancedTerrainLayer.dead-cause-difficult.name", hint: "EnhancedTerrainLayer.dead-cause-difficult.hint", scope: "world", config: true, - default: false, - type: Boolean + choices: tokenoptions, + default: "false", + type: String }); game.settings.register(modulename, 'use-obstacles', { name: "EnhancedTerrainLayer.use-obstacles.name", diff --git a/module.json b/module.json index 72ed4af..49feea7 100644 --- a/module.json +++ b/module.json @@ -1,7 +1,7 @@ { "title": "Enhanced Terrain Layer", "description": "A base module that adds a Terrain Layer to Foundry. Used as a library for Rulers and other modules", - "version": "10.3", + "version": "10.4", "authors": [ { "name": "IronMonk", @@ -47,7 +47,7 @@ "css/terrainlayer.css" ], "url": "https://github.com/ironmonk88/enhanced-terrain-layer", - "download": "https://github.com/ironmonk88/enhanced-terrain-layer/archive/10.3.zip", + "download": "https://github.com/ironmonk88/enhanced-terrain-layer/archive/10.4.zip", "manifest": "https://github.com/ironmonk88/enhanced-terrain-layer/releases/latest/download/module.json", "bugs": "https://github.com/ironmonk88/enhanced-terrain-layer/issues", "allowBugReporter": true,