diff --git a/CHANGELOG.md b/CHANGELOG.md index 16798b9..0861437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## Version 12.01 + +v12 compatibility + +Added the option for the GM to see imageless tiles in v12. + +Updated the game time action to handle hous and minutes better, and to not break when advancing time. + +Fixed issue with Stop Within Tile and Movement Within Tile causing a tile to trigger even if no movement has happened. + +Fixed issue with tokens within Tile when triggering another tile. + +Added the name property to Tiles so you can give them a name, this helps when triggering them from a Region. + +Added Tile Triggering as a behavior in regions. + ## Version 11.27 Increased the precision of the playlist volume slider diff --git a/actions.js b/actions.js index a254ad1..bc7c604 100644 --- a/actions.js +++ b/actions.js @@ -1,4 +1,4 @@ -import { MonksActiveTiles, log, error, actiontext, debug, warn, setting, i18n, makeid, rollDice, getVolume, getValue, asyncFilter } from './monks-active-tiles.js'; +import { MonksActiveTiles, log, error, actiontext, debug, warn, setting, i18n, makeid, rollDice, getVolume, getValue, asyncFilter, rectContains } from './monks-active-tiles.js'; import { BatchManager } from "./classes/BatchManager.js"; export class ActionManager { @@ -14,7 +14,7 @@ export class ActionManager { return arr[0]; else { let results = arr.filter(d => d.dest == undefined || d.dest.id != id); - let idx = Math.clamped(parseInt(Math.random() * results.length), 0, results.length - 1); + let idx = Math.clamp(parseInt(Math.random() * results.length), 0, results.length - 1); return results[idx]; } } @@ -222,7 +222,7 @@ export class ActionManager { dest.x = parseInt(await getValue(dest.x, args, dest, { prop: canvas.scene._viewPosition.x, explicit: true })); dest.y = parseInt(await getValue(dest.y, args, dest, { prop: canvas.scene._viewPosition.y, explicit: true })); - let panUsers = duplicate(showUsers); + let panUsers = foundry.utils.duplicate(showUsers); let runForMe = panUsers.includes(game.user.id); panUsers = panUsers.filter(u => u != game.user.id); @@ -434,7 +434,7 @@ export class ActionManager { let tokenTransfers = {}; for (let tokendoc of entities) { - let loc = duplicate(action.data.location); + let loc = foundry.utils.duplicate(action.data.location); loc.sceneId = loc.sceneId || tokendoc.parent.id; let dests = await MonksActiveTiles.getLocation.call(tile, loc, args); @@ -447,10 +447,10 @@ export class ActionManager { } let dest = ActionManager.pickRandom(dests, tile.id); - let entDest = duplicate(dest); + let entDest = foundry.utils.duplicate(dest); if (!entDest) { console.warn("monks-active-tiles | Could not find a teleport destination", loc); - let newPos = canvas.grid.getSnappedPosition(original.x, original.y); + let newPos = MonksActiveTiles.getSnappedPosition(original.x, original.y); let ray = new Ray({ x: tokendoc.x, y: tokendoc.y }, { x: newPos.x, y: newPos.y }); @@ -497,9 +497,9 @@ export class ActionManager { entDest.x = dest.dest.x + (dest.dest.width / 2); entDest.y = dest.dest.y + (dest.dest.height / 2); } else if (destpos == "relative") { - let usePt = duplicate(pt); + let usePt = foundry.utils.duplicate(pt); if (!["enter", "exit", "click", "dblclick", "rightclick", "dblrightclick"].includes(method) && tile.pointWithin(pt)) - usePt = duplicate(oldPos); + usePt = foundry.utils.duplicate(oldPos); let deltaX1 = (usePt.x - oldTile.x); let deltaY1 = (usePt.y - oldTile.y); @@ -523,8 +523,8 @@ export class ActionManager { if (parseInt(midDestY + deltaY2).toNearest(dest.dest.parent.dimensions.size) == parseInt(midDestY + deltaY2) && deltaY2 > 0) deltaY2 *= 0.99; - entDest.x = Math.clamped(parseInt(midDestX + deltaX2), dest.dest.x, dest.dest.x + dest.dest.width); - entDest.y = Math.clamped(parseInt(midDestY + deltaY2), dest.dest.y, dest.dest.y + dest.dest.height); + entDest.x = Math.clamp(parseInt(midDestX + deltaX2), dest.dest.x, dest.dest.x + dest.dest.width); + entDest.y = Math.clamp(parseInt(midDestY + deltaY2), dest.dest.y, dest.dest.y + dest.dest.height); } else { // Find a random location within this Tile entDest.x = dest.dest.x + Math.floor((Math.random() * Math.abs(dest.dest.width))); @@ -562,7 +562,7 @@ export class ActionManager { if (samescene) { await tokendoc._object?.stopAnimation(); //+++ need to stop the animation for everyone, even if they're not on the same scene - if (!tokendoc.parent.dimensions.rect.contains(newPos.x, newPos.y)) { + if (!rectContains(tokendoc.parent.dimensions.rect, newPos.x, newPos.y)) { //+++find the closest spot on the edge of the scene ui.notifications.error(i18n("MonksActiveTiles.msg.prevent-teleport")); return; @@ -625,7 +625,7 @@ export class ActionManager { newPos.y -= ((scene.dimensions.size * Math.abs(tokendoc.height)) / 2); } - let td = mergeObject(await tokendoc.toObject(), { x: newPos.x, y: newPos.y, 'flags.monks-active-tiles.teleporting': true, 'flags.monks-active-tiles.current': true }); + let td = foundry.utils.mergeObject(await tokendoc.toObject(), { x: newPos.x, y: newPos.y, 'flags.monks-active-tiles.teleporting': true, 'flags.monks-active-tiles.current': true }); if (newtoken) { batch.add("update", newtoken, (action.data.preservesettings ? { x: newPos.x, y: newPos.y, img: tokendoc.texture.src, hidden: tokendoc.hidden, 'flags.monks-active-tiles.teleporting': true, 'flags.monks-active-tiles.current': true } : td), @@ -822,11 +822,11 @@ export class ActionManager { y: entity.y + midY } - let location = duplicate(action.data.location); + let location = foundry.utils.duplicate(action.data.location); let dests = await MonksActiveTiles.getLocation.call(tile, location, Object.assign({}, args, { pt: { x: pt?.x - midX, y: pt?.y - midY } })); let dest = ActionManager.pickRandom(dests); - let entDest = duplicate(dest); + let entDest = foundry.utils.duplicate(dest); if (!entDest) continue; @@ -869,9 +869,9 @@ export class ActionManager { entDest.x = dest.dest.x + (dest.dest.width / 2); entDest.y = dest.dest.y + (dest.dest.height / 2); } else if (action.data.position == "relative") { - let usePt = duplicate(pt); + let usePt = foundry.utils.duplicate(pt); if (!["enter", "exit", "click", "dblclick", "rightclick", "dblrightclick"].includes(method) && tile.pointWithin(pt)) - usePt = duplicate(oldPos); + usePt = foundry.utils.duplicate(oldPos); let deltaX = (usePt.x - oldTile.x); let deltaY = (usePt.y - oldTile.y); @@ -893,8 +893,8 @@ export class ActionManager { let midDestX = dest.dest.x + (Math.abs(dest.dest.width) / 2); let midDestY = dest.dest.y + (Math.abs(dest.dest.height) / 2); - entDest.x = Math.clamped(midDestX + deltaX, dest.dest.x, dest.dest.x + dest.dest.width); - entDest.y = Math.clamped(midDestY + deltaY, dest.dest.y, dest.dest.y + dest.dest.height); + entDest.x = Math.clamp(midDestX + deltaX, dest.dest.x, dest.dest.x + dest.dest.width); + entDest.y = Math.clamp(midDestY + deltaY, dest.dest.y, dest.dest.y + dest.dest.height); } else { // Find a random location within this Tile entDest.x = dest.dest.x + Math.floor((Math.random() * Math.abs(dest.dest.width))); @@ -907,7 +907,7 @@ export class ActionManager { y: entDest.y }; - if (!entity.parent.dimensions.rect.contains(newPos.x, newPos.y)) { + if (!rectContains(entity.parent.dimensions.rect, newPos.x, newPos.y)) { //+++find the closest spot on the edge of the scene ui.notifications.error(i18n("MonksActiveTiles.msg.prevent-teleport")); return; @@ -1282,8 +1282,8 @@ export class ActionManager { entity = entity.actor; } if (entity instanceof JournalEntry) { - if (game.modules.get("monks-enhanced-journal")?.active && entity.pages.size == 1 && (getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.actors") || []).length) { - let eaactors = getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.actors"); + if (game.modules.get("monks-enhanced-journal")?.active && entity.pages.size == 1 && (foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.actors") || []).length) { + let eaactors = foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.actors"); for (let ea of eaactors) { let actor; if (ea.pack) { @@ -1313,7 +1313,7 @@ export class ActionManager { let tdests = (ea.location ? dests.filter(d => d.dest ? Tagger.hasTags(d.dest, ea.location) : d) : dests); let dest = ActionManager.pickRandom(tdests, tile.id); - let entDest = duplicate(dest); + let entDest = foundry.utils.duplicate(dest); if (!entDest) continue; @@ -1387,7 +1387,7 @@ export class ActionManager { } else if (entity instanceof Actor) { let dest = dests[Math.floor(Math.random() * dests.length)]; - let entDest = duplicate(dest); + let entDest = foundry.utils.duplicate(dest); if (entDest) { if (dest.dest instanceof TileDocument) { // Find a random location within this Tile @@ -1442,11 +1442,11 @@ export class ActionManager { // Prepare the Token data const td = await actor.getTokenDocument(); - mergeObject(td, ad.data); + foundry.utils.mergeObject(td, ad.data); if (!ad.lockpos) { if (action.data.avoidtokens) { - let dt = mergeObject(ad.data, MonksActiveTiles.findVacantSpot(ad.data, { data: td }, scene, newTokens, ad.dest, action.data.snap)); + let dt = foundry.utils.mergeObject(ad.data, MonksActiveTiles.findVacantSpot(ad.data, { data: td }, scene, newTokens, ad.dest, action.data.snap)); td.x = dt.x; td.y = dt.y; } @@ -1460,17 +1460,17 @@ export class ActionManager { else { const hw = canvas.grid.w / 2; const hh = canvas.grid.h / 2; - let pos = canvas.grid.getSnappedPosition(td.x - (td.width * hw), td.y - (td.height * hh)) + let pos = MonksActiveTiles.getSnappedPosition(td.x - (td.width * hw), td.y - (td.height * hh)) td.x = pos.x; td.y = pos.y; } } // Validate the final position - if (!canvas.dimensions.rect.contains(td.x, td.y)) continue; + if (!rectContains(canvas.dimensions.rect, td.x, td.y)) continue; //if (td.hidden) - // setProperty(td, "flags.monks-active-tiles.hide", true); + // foundry.utils.setProperty(td, "flags.monks-active-tiles.hide", true); // Submit the Token creation request and activate the Tokens layer (if not already active) batch.add("create", cls, td, { parent: scene }); @@ -1486,7 +1486,7 @@ export class ActionManager { tokens = batch.mergeResults(tokens); //for (let token of tokens) { - // if (getProperty(token, "flags.monks-active-tiles.hidden")) { + // if (foundry.utils.getProperty(token, "flags.monks-active-tiles.hidden")) { // batch.add("update", token, { "hidden": true, "flags.monks-active-tiles.-=hidden": null }); // } //} @@ -1597,13 +1597,13 @@ export class ActionManager { // Snap to Grid if (action.data.snap) { - let snap = canvas.grid.getSnappedPosition(data.x, data.y, canvas.notes.gridPrecision); + let snap = MonksActiveTiles.getSnappedPosition(data.x, data.y, 2); data.x = snap.x; data.y = snap.y; } // Validate the final position - if (!canvas.dimensions.rect.contains(data.x, data.y)) return; + if (!rectContains(canvas.dimensions.rect, data.x, data.y)) return; batch.add("create", cls, data, { parent: tile.parent }); @@ -1803,27 +1803,27 @@ export class ActionManager { for (let entity of entities) { if (entity) { let base = entity; - let val = duplicate(_val); - let attr = duplicate(_attr); + let val = foundry.utils.duplicate(_val); + let attr = foundry.utils.duplicate(_attr); let update = {}; if (!attr.startsWith('flags')) { - if (!hasProperty(base, attr) && entity instanceof TokenDocument) { + if (!foundry.utils.hasProperty(base, attr) && entity instanceof TokenDocument) { base = entity.actor; } - if (!hasProperty(base, attr)) { + if (!foundry.utils.hasProperty(base, attr)) { if (!attr.startsWith("system")) attr = 'system.' + attr; - if (!hasProperty(base, attr)) { + if (!foundry.utils.hasProperty(base, attr)) { warn("Couldn't find attribute", entity, attr); continue; } } } - let prop = getProperty(base, attr); + let prop = foundry.utils.getProperty(base, attr); if (prop && typeof prop == 'object' && !(prop instanceof Array)) { if (prop.value == undefined) { @@ -2074,7 +2074,7 @@ export class ActionManager { let updates = {}; amount = Math.floor(parseInt(amount)); let resourcename = game.system.primaryTokenAttribute || 'attributes.hp'; - let resource = getProperty(actor, "system." + resourcename); + let resource = foundry.utils.getProperty(actor, "system." + resourcename); if (resource instanceof Object) { // Deduct damage from temp HP first let dt = 0; @@ -2090,7 +2090,7 @@ export class ActionManager { } // Update the Actor - const dh = Math.clamped(resource.value - (amount - dt), (game.system.id == 'D35E' || game.system.id == 'pf1' ? -2000 : 0), (resource.max == 0 ? 4000 : resource.max + tmpMax)); + const dh = Math.clamp(resource.value - (amount - dt), (game.system.id == 'D35E' || game.system.id == 'pf1' ? -2000 : 0), (resource.max == 0 ? 4000 : resource.max + tmpMax)); updates["system." + resourcename + ".value"] = dh; } else { let value = Math.floor(parseInt(resource)); @@ -2120,7 +2120,7 @@ export class ActionManager { token: entity.toObject(false), tile: tile.toObject(false), entity: entity, - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), value: value, scene: canvas.scene, @@ -2168,7 +2168,7 @@ export class ActionManager { await a.applyDamage({ damage: val, token: entity }); else if (game.system.id == "pf1") await a.applyDamage(val); - else if (game.system.id == "dnd5e" && isNewerVersion(game.system.version, "2.9.9")) + else if (game.system.id == "dnd5e" && foundry.utils.isNewerVersion(game.system.version, "2.9.9")) await a.applyDamage(val, { multiplier: 1 }); else await a.applyDamage(val, 1); @@ -2302,7 +2302,7 @@ export class ActionManager { return tile._sounds[action.id]; } - let volume = Math.clamped((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); + let volume = Math.clamp((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); let audiofiles = await getTileSounds(tile); const audiofile = audiofiles[Math.floor(Math.random() * audiofiles.length)]; @@ -2334,13 +2334,13 @@ export class ActionManager { return; let fade = action.data.fade ?? 0; - AudioHelper.play({ src: audiofile, volume: (fade > 0 ? 0 : volume * getVolume()), loop: action.data.loop }, false).then((sound) => { + foundry.audio.AudioHelper.play({ src: audiofile, volume: (fade > 0 ? 0 : volume * getVolume()), loop: action.data.loop }, false).then((sound) => { if (fade > 0) sound.fade(volume * getVolume(), { duration: fade * 1000 }); if (tile.soundeffect == undefined) tile.soundeffect = {}; tile.soundeffect[action.id] = sound; - tile.soundeffect[action.id].on("stop", () => { + tile.soundeffect[action.id].addEventListener("stop", () => { MonksActiveTiles.emit('stopsound', { tileid: tile.uuid, actionid: action.id, @@ -2349,7 +2349,7 @@ export class ActionManager { }); delete tile.soundeffect[action.id]; }); - tile.soundeffect[action.id].on("end", () => { + tile.soundeffect[action.id].addEventListener("end", () => { debug('Finished playing', audiofile); delete tile.soundeffect[action.id]; }); @@ -2468,7 +2468,7 @@ export class ActionManager { else { let options = { }; if (Number.isNumeric(action.data.volume.value ?? action.data.volume)) { - options.volume = Math.clamped((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); + options.volume = Math.clamp((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); } await entity.playAll(options); } @@ -2480,7 +2480,7 @@ export class ActionManager { else { let update = { playing: true, repeat: action.data.loop }; if (Number.isNumeric(action.data.volume.value ?? action.data.volume)) { - update.volume = Math.clamped((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); + update.volume = Math.clamp((action.data.volume.value ?? action.data.volume ?? 1), 0, 1); } batch.add("update", entity, update); @@ -3044,7 +3044,7 @@ export class ActionManager { if (action.data.chatbubble !== "false") { if (tkn instanceof Token) { - let su = duplicate(showUsers); + let su = foundry.utils.duplicate(showUsers); if (su.includes(game.user.id) && canvas.scene.id == tkn.document.parent.id) { canvas.hud.bubbles.say(tkn, content); su = su.filter(u => u != game.user.id); @@ -3062,7 +3062,7 @@ export class ActionManager { let messageData = { user: userId, speaker: speaker, - type: (action.data.incharacter ? CONST.CHAT_MESSAGE_TYPES.IC : CONST.CHAT_MESSAGE_TYPES.OOC), + style: (action.data.incharacter ? CONST.CHAT_MESSAGE_STYLES.IC : CONST.CHAT_MESSAGE_STYLES.OOC), content: content }; @@ -3080,7 +3080,7 @@ export class ActionManager { if (action.data.language != '' && game.modules.get("polyglot")?.active) { let language = action.data.language.indexOf(":") > -1 ? action.data.language.split(":")[1] : action.data.language; if (!!language) - mergeObject(messageData, { flags: { 'monks-active-tiles': { language } }, lang: language }); + foundry.utils.mergeObject(messageData, { flags: { 'monks-active-tiles': { language } }, lang: language }); } await ChatMessage.create(messageData, { chatBubble: false }); @@ -3369,7 +3369,7 @@ export class ActionManager { flavor: `Draws ${nr} from the ${rolltable.name} table.`, user: userId, speaker: speaker, - type: CONST.CHAT_MESSAGE_TYPES.ROLL, + style: CONST.CHAT_MESSAGE_STYLES.ROLL, roll: tblResults.roll, sound: tblResults.roll ? CONFIG.sounds.dice : null, flags: { "core.RollTable": rolltable.id } @@ -3379,7 +3379,7 @@ export class ActionManager { let description = await TextEditor.enrichHTML(rolltable.description, { documents: true, entities: true, async: true }) messageData.content = await renderTemplate(CONFIG.RollTable.resultTemplate, { description: description, - results: duplicate(tblResults.results).map(r => { + results: foundry.utils.duplicate(tblResults.results).map(r => { let original = tblResults.results.find(res => res.id == r._id); r.text = original?.getChatText() || r.text; r.icon = r.icon || r.img; @@ -3858,7 +3858,7 @@ export class ActionManager { if (/^JournalEntry.[a-zA-Z0-9]{16}$/.test(value) || /^Compendium.+[a-zA-Z0-9]{16}$/.test(value)) { let entity = await fromUuid(value); - if (entity && !(entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { + if (entity && !(entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { let list = { "": "" }; for (let p of entity.pages) list[p._id] = p.name; @@ -3879,7 +3879,7 @@ export class ActionManager { if (/^JournalEntry.[a-zA-Z0-9]{16}$/.test(value.id) || /^Compendium.+[a-zA-Z0-9]{16}$/.test(value.id)) { let entity = await fromUuid(value.id); if (entity) - return !(entity && entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")); + return !(entity && entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")); } } catch { } } @@ -3899,7 +3899,7 @@ export class ActionManager { if (/^JournalEntry.[a-zA-Z0-9]{16}$/.test(value.id) || /^Compendium.+[a-zA-Z0-9]{16}$/.test(value.id)) { let entity = await fromUuid(value.id); if (entity) - return !(entity && entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")); + return !(entity && entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")); } } catch { } } @@ -3973,8 +3973,8 @@ export class ActionManager { let showUsers = MonksActiveTiles.getForPlayers(showto, args); if (showUsers.includes(game.user.id)) { - if (game.modules.get("monks-enhanced-journal")?.active && entity instanceof JournalEntry && entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")) { - let type = getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"); + if (game.modules.get("monks-enhanced-journal")?.active && entity instanceof JournalEntry && entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type")) { + let type = foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"); if (type == "base" || type == "oldentry") type = "journalentry"; let types = game.MonksEnhancedJournal.getDocumentTypes(); if (types[type]) { @@ -3983,7 +3983,7 @@ export class ActionManager { } } - if (action.data.asimage && (entity.type == "image" || getProperty(entity, "flags.monks-enhanced-journal.type") == "picture")) { + if (action.data.asimage && (entity.type == "image" || foundry.utils.getProperty(entity, "flags.monks-enhanced-journal.type") == "picture")) { new ImagePopout(entity.src).render(true); } else { let anchor = action.data.subsection?.slugify().replace(/["']/g, "").substring(0, 64); @@ -4177,9 +4177,9 @@ export class ActionManager { let quantityName = item.system.quantity != undefined ? "quantity" : item.system.value != undefined ? "value" : item.system.eqt != undefined ? "eqt.count" : null; if (quantityName) { let valueName = `system.${quantityName}.value`; - let useValue = getProperty(item, valueName) != undefined; + let useValue = foundry.utils.getProperty(item, valueName) != undefined; - setProperty(itemData, `system.${quantityName}`, useValue ? { value: quantity } : quantity); + foundry.utils.setProperty(itemData, `system.${quantityName}`, useValue ? { value: quantity } : quantity); } } let hasAdded = false; @@ -4369,7 +4369,7 @@ export class ActionManager { if (/^JournalEntry.[a-zA-Z0-9]{16}$/.test(value)) { let entity = await fromUuid(value); - if (entity && !(entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { + if (entity && !(entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { let list = { "": "" }; for (let p of entity.pages) list[p._id] = p.name; @@ -4800,7 +4800,7 @@ export class ActionManager { if (!(entity instanceof TileDocument)) continue; - if (getProperty(entity, "flags.monks-active-tiles.active") === false && action.data?.allowdisabled !== true) + if (foundry.utils.getProperty(entity, "flags.monks-active-tiles.active") === false && action.data?.allowdisabled !== true) continue; let landing = await getValue(action.data?.landing, args, entity); @@ -4810,7 +4810,7 @@ export class ActionManager { actor: tokens[0]?.actor?.toObject(false), token: tokens[0]?.toObject(false), tile: tile.toObject(false), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, entity: entity, user: game.users.get(userId), value: value, @@ -4838,7 +4838,7 @@ export class ActionManager { let value = {}; for (let result of results) { - mergeObject(value, result.value); + foundry.utils.mergeObject(value, result.value); } return value; }); @@ -5082,7 +5082,7 @@ export class ActionManager { if (!(entity instanceof TokenDocument)) continue; - let prop = getProperty(entity, 'elevation'); + let prop = foundry.utils.getProperty(entity, 'elevation'); if (prop == undefined) { warn("Couldn't find attribute", entity); @@ -5097,7 +5097,7 @@ export class ActionManager { actor: tokens[0]?.actor?.toObject(false), token: tokens[0]?.toObject(false), tile: tile.toObject(false), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, entity: entity, user: game.users.get(userId), value: value, @@ -5345,7 +5345,7 @@ export class ActionManager { let entities = await MonksActiveTiles.getEntities(args, 'tiles'); let getPosition = async function (entity) { - let fileindex = getProperty(entity, 'flags.monks-active-tiles.fileindex') || 0; + let fileindex = foundry.utils.getProperty(entity, 'flags.monks-active-tiles.fileindex') || 0; let position = await getValue(action.data?.select ?? "next", args, entity, { fileindex: fileindex, files: entity._images @@ -5377,7 +5377,7 @@ export class ActionManager { } else position = parseInt(position); - position = Math.clamped(position, 1, entity._images.length); + position = Math.clamp(position, 1, entity._images.length); return position; } @@ -5476,7 +5476,7 @@ export class ActionManager { entityid: entity.uuid, from: entity.texture.src, transition: getTransition(), - transitionId: randomID(), + transitionId: foundry.utils.randomID(), img: entity._images[position - 1], time: time, position: position - 1 @@ -5509,7 +5509,7 @@ export class ActionManager { data.img = entity._images[data.position]; data.time = new Date().getTime() + (action.data?.speed * 1000); - setProperty(entity, 'flags.monks-active-tiles.fileindex', data.position); + foundry.utils.setProperty(entity, 'flags.monks-active-tiles.fileindex', data.position); return doNextPromise(data); } else { @@ -5802,10 +5802,38 @@ export class ActionManager { fn: async (args = {}) => { let { action } = args; - let time = await getValue(action.data.time, args, null, { prop: game.time.worldTime }); - time = parseInt(time) * 60; - if (time && !isNaN(time)) { - game.time.advance(time); + let time = action.data.time; + // strip off a leading + or - sign + let relative = false; + if (action.data.time.startsWith('+') || action.data.time.startsWith('-')) { + relative = action.data.time.substring(0, 1); + time = action.data.time.substring(1).trim(); + } + + time = await getValue(time, args, null, { prop: game.time.worldTime }); + time = time + ""; + + // convert string time to seconds + let seconds = 0; + if (time.includes(':')) { + let parts = time.split(':'); + seconds = parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + (parts.length > 2 ? parseInt(parts[2]) : 0); + } else { + seconds = parseInt(time) * 60; + } + + if (seconds && !isNaN(seconds)) { + if (!relative) { + // get the world time, and set the time part to the new time + let worldTime = MonksActiveTiles.getWorldTime(); + // get the difference between the new time and the current time + let diff = seconds - (worldTime * 60); + // advance the game time to the difference + game.time.advance(diff); + } else { + // relative time + game.time.advance(seconds * (relative == "-" ? -1 : 1)); + } } }, content: async (trigger, action) => { @@ -5951,7 +5979,7 @@ export class ActionManager { actor: tokens[0]?.actor?.toObject(), token: tokens[0]?.toObject(), tile: tile, - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), players: game.users, value: value, @@ -6306,7 +6334,7 @@ export class ActionManager { if (/^JournalEntry.[a-zA-Z0-9]{16}$/.test(value)) { let entity = await fromUuid(value); - if (entity && !(entity.pages.size == 1 && !!getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { + if (entity && !(entity.pages.size == 1 && !!foundry.utils.getProperty(entity.pages.contents[0], "flags.monks-enhanced-journal.type"))) { let list = { "": "" }; for (let p of entity.pages) list[p._id] = p.name; @@ -6526,7 +6554,7 @@ export class ActionManager { if (entity instanceof TileDocument) { let name = await getValue(action.data.name, args, entity, { timestamp: new Date().toLocaleString() }); - let variables = getProperty(entity, "flags.monks-active-tiles.variables") || {}; + let variables = foundry.utils.getProperty(entity, "flags.monks-active-tiles.variables") || {}; let w = name.replace(/[.+^${}()|[\]\\]/g, '\\$&'); const re = new RegExp(`^${w.replace(/\*/g, '.*').replace(/\?/g, '.')}$`, 'i'); let keys = name.includes("*") || name.includes("?") ? Object.keys(variables).filter(k => { @@ -6537,10 +6565,10 @@ export class ActionManager { let val = await getValue(action.data.value, args, entity, { timestamp: new Date().toLocaleString(), prop }); if (val == "_null") { - setProperty(entity, `flags.monks-active-tiles.variables.${key}`, null); + foundry.utils.setProperty(entity, `flags.monks-active-tiles.variables.${key}`, null); await entity.unsetFlag("monks-active-tiles", `variables.${key}`); } else { - setProperty(entity, `flags.monks-active-tiles.variables.${key}`, val); + foundry.utils.setProperty(entity, `flags.monks-active-tiles.variables.${key}`, val); await entity.setFlag("monks-active-tiles", `variables.${key}`, val); } } @@ -7002,7 +7030,7 @@ export class ActionManager { return false; const tolerance = Math.min(t.w, t.h) / 4; - return canvas.effects.visibility.testVisibility({ x: midTarget.x, y: midTarget.y }, { tolerance, object: t }); + return canvas.visibility.testVisibility({ x: midTarget.x, y: midTarget.y }, { tolerance, object: t }); }); let cont = (action.data?.continue == 'always' @@ -7092,7 +7120,7 @@ export class ActionManager { actor: tokens[0]?.actor?.toObject(false), token: tokens[0]?.toObject(false), tile: tile.toObject(false), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), value: value, scene: canvas.scene, @@ -7174,7 +7202,7 @@ export class ActionManager { actor: tokens[0]?.actor?.toObject(false), token: tokens[0]?.toObject(false), tile: tile.toObject(false), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), value: value, scene: canvas.scene, @@ -7348,7 +7376,7 @@ export class ActionManager { else position = position - 1; - position = Math.clamped(position, 0, entities.length - 1); + position = Math.clamp(position, 0, entities.length - 1); entity = entities[position]; } @@ -7443,8 +7471,8 @@ export class ActionManager { let found = false; if (!attr.startsWith('flags')) { - if (!hasProperty(base, attr) && entity instanceof TokenDocument) { - if (hasProperty(base, "system." + attr) && entity instanceof TokenDocument) { + if (!foundry.utils.hasProperty(base, attr) && entity instanceof TokenDocument) { + if (foundry.utils.hasProperty(base, "system." + attr) && entity instanceof TokenDocument) { attr = "system." + attr; found = true; } else @@ -7452,14 +7480,14 @@ export class ActionManager { } if (!found) { - if (!hasProperty(base, attr)) { - if (hasProperty(base, "system." + attr)) + if (!foundry.utils.hasProperty(base, attr)) { + if (foundry.utils.hasProperty(base, "system." + attr)) attr = "system." + attr; } } } - prop = getProperty(base, attr) || prop; + prop = foundry.utils.getProperty(base, attr) || prop; if (prop && (typeof prop == 'object') && !(prop instanceof Array) && !(prop instanceof Set)) { if (prop.value == undefined) { @@ -7774,7 +7802,7 @@ export class ActionManager { if (entity instanceof TileDocument) { count++; let name = await getValue(action.data?.name, args, entity, { operation: 'compare' }); - let cando = await getValue(action.data?.value, args, entity, { prop: getProperty(entity, `flags.monks-active-tiles.variables.${name}`), operation: 'compare' }); + let cando = await getValue(action.data?.value, args, entity, { prop: foundry.utils.getProperty(entity, `flags.monks-active-tiles.variables.${name}`), operation: 'compare' }); if (cando) success++; } @@ -7819,7 +7847,7 @@ export class ActionManager { const { tile, tokens, action, userId, value, method, change } = args; let name = await getValue(action.data?.name, args, null, { operation: 'compare' }); - let prop = !!name ? getProperty(value, name) ?? getProperty(args, name) : ""; + let prop = !!name ? foundry.utils.getProperty(value, name) ?? foundry.utils.getProperty(args, name) : ""; let cando = await getValue(action.data?.value, args, null, { prop, operation: 'compare' }); if (cando) @@ -7864,20 +7892,20 @@ export class ActionManager { let base = tile; if (!attr.startsWith('flags')) { - if (!hasProperty(base, attr) && entity instanceof TokenDocument) { + if (!foundry.utils.hasProperty(base, attr) && entity instanceof TokenDocument) { base = entity.actor; } - if (!hasProperty(base, attr)) { + if (!foundry.utils.hasProperty(base, attr)) { if (!attr.startsWith("system")) attr = 'system.' + attr; - if (!hasProperty(base, attr)) { + if (!foundry.utils.hasProperty(base, attr)) { warn("Couldn't find attribute", entity, attr); } } } - let prop = getProperty(base, attr); + let prop = foundry.utils.getProperty(base, attr); if (prop && typeof prop == 'object' && !(prop instanceof Array)) { if (prop.value == undefined) { @@ -8176,7 +8204,7 @@ export class ActionManager { let _tag = action.data?.tag; let goto = await Promise.all(entities.map(async (e) => { - let tag = await getValue(duplicate(_tag), args, null, { prop: e }); + let tag = await getValue(foundry.utils.duplicate(_tag), args, null, { prop: e }); return { tag: tag, entities: [e] @@ -8549,7 +8577,7 @@ Hooks.on("setupTileActions", (app) => { actor: tokens[0]?.actor?.toObject(false), token: tokens[0]?.toObject(false), tile: tile.toObject(), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), value: value, scene: canvas.scene, diff --git a/apps/action-config.js b/apps/action-config.js index f5dac54..1514d44 100644 --- a/apps/action-config.js +++ b/apps/action-config.js @@ -130,7 +130,7 @@ export class ActionConfig extends FormApplication { return result; }, {});*/ - return mergeObject(super.getData(options), { + return foundry.utils.mergeObject(super.getData(options), { availableActions: availableActions }); } @@ -255,7 +255,7 @@ export class ActionConfig extends FormApplication { } else if (data.type == "button") { // Call the drop handler if (target && target.dataset.id) { - let items = duplicate(this.buttonlist); + let items = foundry.utils.duplicate(this.buttonlist); if (data.id === target.dataset.id) return; // Don't drop on yourself @@ -508,7 +508,7 @@ export class ActionConfig extends FormApplication { } static async addTag(event) { - let data = expandObject(this._getSubmitData()); + let data = foundry.utils.expandObject(this._getSubmitData()); let prop = event.currentTarget.dataset["target"] let entity = $(`input[name="${prop}"]`).data("value") || {}; entity["tag-name"] = entity?.id?.substring(7); @@ -563,7 +563,7 @@ export class ActionConfig extends FormApplication { if (!temporaryIds?.[tag]) { temporaryIds[tag] = [] } - id = randomID(); + id = foundry.utils.randomID(); temporaryIds[tag].push(id); } return tag.replace(regx, id); @@ -626,7 +626,7 @@ export class ActionConfig extends FormApplication { } async editEntityId(event) { - let data = expandObject(super._getSubmitData()); + let data = foundry.utils.expandObject(super._getSubmitData()); let entity = JSON.parse(data?.data?.entity || "{}"); const html = await renderTemplate(`modules/monks-active-tiles/templates/entity-dialog.html`, { @@ -663,7 +663,7 @@ export class ActionConfig extends FormApplication { sceneList[scene.id] = scene.name; } - let data = expandObject(super._getSubmitData()); + let data = foundry.utils.expandObject(super._getSubmitData()); let location = JSON.parse(data?.data?.location || "{}"); const html = await renderTemplate(`modules/monks-active-tiles/templates/location-dialog.html`, { @@ -706,7 +706,7 @@ export class ActionConfig extends FormApplication { /* async editEntityId(event) { - let data = expandObject(super._getSubmitData()); + let data = foundry.utils.expandObject(super._getSubmitData()); new EntityEdit($(event.currentTarget).prev(), { action: data.action }).render(true); } @@ -749,7 +749,7 @@ export class ActionConfig extends FormApplication { let buttons = JSON.parse($('input[name="data.buttons"', this.element).val() || "[]"); if (!data.id) { - data.id = randomID(); + data.id = foundry.utils.randomID(); buttons.push(data); } else { let button = buttons.find(b => b.id == data.id); @@ -819,7 +819,7 @@ export class ActionConfig extends FormApplication { } _getSubmitData(updateData = {}) { - let data = expandObject(super._getSubmitData(updateData)); + let data = foundry.utils.expandObject(super._getSubmitData(updateData)); let files = null; if (data.files) { @@ -844,10 +844,10 @@ export class ActionConfig extends FormApplication { */ $('input.range-value', this.element).each(function () { - if ($(this).val() == "") setProperty(data, $(this).prev().attr("name"), ""); + if ($(this).val() == "") foundry.utils.setProperty(data, $(this).prev().attr("name"), ""); }); - return flattenObject(data); + return foundry.utils.flattenObject(data); } async _updateObject(event, formData) { @@ -872,15 +872,15 @@ export class ActionConfig extends FormApplication { formData['data.attack'] = { id: formData['data.attack'], name: $('select[name="data.attack"] option:selected', this.element).text()}; if (this.object.id == undefined) { - mergeObject(this.object, formData); + foundry.utils.mergeObject(this.object, formData); this.object.id = makeid(); - let actions = duplicate(this.options.parent.object.getFlag("monks-active-tiles", "actions") || []); + let actions = foundry.utils.duplicate(this.options.parent.object.getFlag("monks-active-tiles", "actions") || []); let append = this.options.index === -1 || this.options.index === actions.length; if (append) actions.push(this.object); else actions.splice(this.options.index, 0, this.object); - mergeObject(this.options.parent.object.flags, { + foundry.utils.mergeObject(this.options.parent.object.flags, { "monks-active-tiles": { actions: actions } }); //add this row to the parent @@ -905,7 +905,7 @@ export class ActionConfig extends FormApplication { this.options.parent.setPosition({height: 'auto'}); } else { - let actions = duplicate(this.options.parent.object.getFlag("monks-active-tiles", "actions") || []); + let actions = foundry.utils.duplicate(this.options.parent.object.getFlag("monks-active-tiles", "actions") || []); let action = actions.find(a => a.id == this.object.id); if (action) { //clear out these before saving the new information so we don't get data bleed through @@ -918,7 +918,7 @@ export class ActionConfig extends FormApplication { if (this.options.parent.object._sounds) { this.options.parent.object._sounds[this.object.id] = []; } - mergeObject(action, formData); + foundry.utils.mergeObject(action, formData); this.options.parent.object.flags["monks-active-tiles"].actions = actions; //update the text for this row let trigger = MonksActiveTiles.triggerActions[action.action]; @@ -965,7 +965,7 @@ export class ActionConfig extends FormApplication { //$('.gmonly', this.element).toggle(action.requiresGM); for (let ctrl of (action?.ctrls || [])) { - let options = mergeObject({ hide: [], show: [] }, ctrl.options); + let options = foundry.utils.mergeObject({ hide: [], show: [] }, ctrl.options); let field = $('
').addClass('form-fields').data('ctrl', ctrl); if (ctrl["class"]) field.addClass(ctrl["class"]); let id = 'data.' + ctrl.id + (ctrl.variation ? '.value' : ''); diff --git a/apps/active-tile-config.js b/apps/active-tile-config.js index ceaa533..64ad103 100644 --- a/apps/active-tile-config.js +++ b/apps/active-tile-config.js @@ -23,8 +23,8 @@ export const WithActiveTileConfig = (TileConfig) => { constructor(...args) { super(...args); - if (getProperty(this.object, "flags.monks-active-tiles") == undefined) { - this.object.flags = mergeObject(this.object.flags, { + if (foundry.utils.getProperty(this.object, "flags.monks-active-tiles") == undefined) { + this.object.flags = foundry.utils.mergeObject(this.object.flags, { 'monks-active-tiles': { active: true, trigger: setting('default-trigger'), @@ -112,7 +112,7 @@ export const WithActiveTileConfig = (TileConfig) => { let tab = $('
').addClass('tab').attr('data-tab', "triggers").css({ "position": "relative" }).insertAfter($('div[data-tab="animation"]', html)); let template = "modules/monks-active-tiles/templates/tile-config.html"; - const tiledata = mergeObject({ 'data.flags.monks-active-tiles.minrequired': 0 }, data); + const tiledata = foundry.utils.mergeObject({ 'data.flags.monks-active-tiles.minrequired': 0 }, data); tiledata.triggerModes = MonksActiveTiles.triggerModes; tiledata.triggerRestriction = { 'all': i18n("MonksActiveTiles.restrict.all"), 'player': i18n("MonksActiveTiles.restrict.player"), 'gm': i18n("MonksActiveTiles.restrict.gm") }; @@ -161,7 +161,7 @@ export const WithActiveTileConfig = (TileConfig) => { a.marker = currentLanding; a.landingStop = a.data.stop; } - a.landings = duplicate(landings); + a.landings = foundry.utils.duplicate(landings); } } @@ -241,12 +241,12 @@ export const WithActiveTileConfig = (TileConfig) => { if (data.tileId != this.object.id) { if (data.collection == list.dataset.collection) { let src = canvas.scene.tiles.get(data.tileId); - let action = getProperty(src, "flags.monks-active-tiles.actions")?.find(a => a.id == data.id); + let action = foundry.utils.getProperty(src, "flags.monks-active-tiles.actions")?.find(a => a.id == data.id); if (action) { - let newAction = duplicate(action); + let newAction = foundry.utils.duplicate(action); newAction.id = makeid(); - let items = duplicate(this[list.dataset.collection]); + let items = foundry.utils.duplicate(this[list.dataset.collection]); if (items.length && !target) target = $(`li[data-id="${items[0].id}"]`, this.element).get(0); let to = items.findIndex(a => a.id == target?.dataset.id) || 0; @@ -267,7 +267,7 @@ export const WithActiveTileConfig = (TileConfig) => { } else { // Call the drop handler if (target && target.dataset.id) { - let items = duplicate(this[list.dataset.collection]); + let items = foundry.utils.duplicate(this[list.dataset.collection]); if (data.id === target.dataset.id) return; // Don't drop on yourself @@ -324,7 +324,7 @@ export const WithActiveTileConfig = (TileConfig) => { this.object._images = await MonksActiveTiles.getTileFiles(this.object.flags["monks-active-tiles"].files || []); if (!this.object.id && this.object._images.length) { - let fileindex = Math.clamped(this.object.flags["monks-active-tiles"].fileindex, 0, this.object._images.length - 1); + let fileindex = Math.clamp(this.object.flags["monks-active-tiles"].fileindex, 0, this.object._images.length - 1); if (this.object._images[fileindex] != this.object.texture.src) { formData["texture.src"] = this.object._images[fileindex]; } @@ -336,7 +336,7 @@ export const WithActiveTileConfig = (TileConfig) => { await super._updateObject(event, formData); if (this.object.id && this.object._images.length) { - let fileindex = Math.clamped(this.object.flags["monks-active-tiles"].fileindex, 0, this.object._images.length - 1); + let fileindex = Math.clamp(this.object.flags["monks-active-tiles"].fileindex, 0, this.object._images.length - 1); if (this.object._images[fileindex] != this.object.texture.src) { await this.object.update({ texture: { src: this.object._images[fileindex] } }); } @@ -469,9 +469,9 @@ export const WithActiveTileConfig = (TileConfig) => { let result = this.addFile(id, filename); $(event.currentTarget).val(''); if (result) { - let files = duplicate(this.files); + let files = foundry.utils.duplicate(this.files); files.push(result); - mergeObject(this.object.flags, { + foundry.utils.mergeObject(this.object.flags, { "monks-active-tiles": { files: files } }); } @@ -502,7 +502,7 @@ export const WithActiveTileConfig = (TileConfig) => { // Retrieve wildcard content try { const content = await FilePicker.browse(source, pattern, browseOptions); - let files = duplicate(this.files); + let files = foundry.utils.duplicate(this.files); for (let file of content.files) { let ext = file.substr(file.lastIndexOf('.') + 1); if (CONST.IMAGE_FILE_EXTENSIONS[ext] != undefined) { @@ -511,7 +511,7 @@ export const WithActiveTileConfig = (TileConfig) => { files.push(result); } } - mergeObject(this.object.flags, { + foundry.utils.mergeObject(this.object.flags, { "monks-active-tiles": { files: files } }); this.setPosition({ height: 'auto' }); @@ -546,16 +546,16 @@ export const WithActiveTileConfig = (TileConfig) => { $(`input[name="flags.monks-active-tiles.fileindex"]`, this.element).val(idx); - mergeObject(this.object.flags, { + foundry.utils.mergeObject(this.object.flags, { "monks-active-tiles": { fileindex: idx } }); } removeFile(event) { let id = event.currentTarget.closest('.file-row').dataset["id"]; - let files = duplicate(this.files); + let files = foundry.utils.duplicate(this.files); files.findSplice(i => i.id == id); - mergeObject(this.object.flags, { + foundry.utils.mergeObject(this.object.flags, { "monks-active-tiles": { files: files } }); @@ -583,9 +583,9 @@ export const WithActiveTileConfig = (TileConfig) => { } deleteAction(id) { - let actions = duplicate(this.actions); + let actions = foundry.utils.duplicate(this.actions); actions.findSplice(i => i.id == id); - mergeObject(this.object.flags, { + foundry.utils.mergeObject(this.object.flags, { "monks-active-tiles": { actions: actions } }); //this.object.setFlag("monks-active-tiles", "actions", actions); @@ -609,7 +609,7 @@ export const WithActiveTileConfig = (TileConfig) => { } cloneAction(id) { - let actions = duplicate(this.actions); + let actions = foundry.utils.duplicate(this.actions); let idx = actions.findIndex(obj => obj.id == id); if (idx == -1) return; @@ -618,13 +618,13 @@ export const WithActiveTileConfig = (TileConfig) => { if (!action) return; - let clone = duplicate(action); + let clone = foundry.utils.duplicate(action); clone.id = makeid(); actions.splice(idx + 1, 0, clone); //if (this.object.id) { // this.object.setFlag("monks-active-tiles", "actions", actions); //} else { - setProperty(this.object, "flags.monks-active-tiles.actions", actions); + foundry.utils.setProperty(this.object, "flags.monks-active-tiles.actions", actions); this.render(); //} } diff --git a/apps/entity-edit.js b/apps/entity-edit.js index a9e7360..8a3291f 100644 --- a/apps/entity-edit.js +++ b/apps/entity-edit.js @@ -23,7 +23,7 @@ export class EntityEdit extends FormApplication { } getData(options) { - return mergeObject(super.getData(options), { + return foundry.utils.mergeObject(super.getData(options), { action: this.options.action, entities: this.entityList }); diff --git a/apps/location-edit.js b/apps/location-edit.js index 5140562..7ee4670 100644 --- a/apps/location-edit.js +++ b/apps/location-edit.js @@ -24,7 +24,7 @@ export class LocationEdit extends FormApplication { sceneList[scene.id] = scene.name; } - return mergeObject(super.getData(options), { + return foundry.utils.mergeObject(super.getData(options), { action: this.options.action, locations: this.locationList, sceneList diff --git a/apps/template-config.js b/apps/template-config.js index be473aa..610a496 100644 --- a/apps/template-config.js +++ b/apps/template-config.js @@ -21,13 +21,13 @@ export class TemplateConfig extends FormApplication { getData(options) { let data = super.getData(options) - let tileData = duplicate(this.object); + let tileData = foundry.utils.duplicate(this.object); delete tileData._id; delete tileData.id; delete tileData.x; delete tileData.y; - return mergeObject(data, { + return foundry.utils.mergeObject(data, { tileData: JSON.stringify(tileData, null, 4), allowEditing: setting("tile-edit") }); diff --git a/apps/tile-history.js b/apps/tile-history.js index 3552769..0ce5fbd 100644 --- a/apps/tile-history.js +++ b/apps/tile-history.js @@ -19,7 +19,7 @@ export class TileHistory extends FormApplication { getData(options) { let history = this.object.getHistory(); - return mergeObject(super.getData(options), { + return foundry.utils.mergeObject(super.getData(options), { history: history }); } diff --git a/apps/tile-templates.js b/apps/tile-templates.js index 2f02e1e..a8d9244 100644 --- a/apps/tile-templates.js +++ b/apps/tile-templates.js @@ -53,19 +53,19 @@ export class TileTemplates extends DocumentDirectory { label: "Tiles" }, deleteDocuments: async (ids) => { - let templates = duplicate(setting("tile-templates") || []); + let templates = foundry.utils.duplicate(setting("tile-templates") || []); for (let id of ids) templates.findSplice(t => t._id == id); await game.settings.set("monks-active-tiles", "tile-templates", templates); new TileTemplates().render(true); }, createDocuments: async (items) => { - let templates = duplicate(setting("tile-templates") || []); + let templates = foundry.utils.duplicate(setting("tile-templates") || []); for (let data of items) { - let _data = duplicate(data); + let _data = foundry.utils.duplicate(data); let doc = new TileDocument(_data); let template = doc.toObject(); - template._id = template.id = randomID(); + template._id = template.id = foundry.utils.randomID(); template.name = data.name; template.visible = true; template.folder = data.folder; @@ -87,9 +87,9 @@ export class TileTemplates extends DocumentDirectory { let tile = data.find(t => t._id === id); if (!tile) return null; tile.canUserModify = () => { return true; }; - tile.toObject = () => { return duplicate(tile); }; + tile.toObject = () => { return foundry.utils.duplicate(tile); }; tile.toCompendium = () => { - let data = deepClone(tile); + let data = foundry.utils.deepClone(tile); delete data._id; delete data.folder; delete data.sort; @@ -301,7 +301,7 @@ export class TileTemplates extends DocumentDirectory { }*/ async updateTile(data) { - let templates = duplicate(this.collection); + let templates = foundry.utils.duplicate(this.collection); if (!data.id) return; @@ -310,7 +310,7 @@ export class TileTemplates extends DocumentDirectory { if (!template) return; - mergeObject(template, data); + foundry.utils.mergeObject(template, data); await game.settings.set("monks-active-tiles", "tile-templates", templates); this.render(true); @@ -361,17 +361,17 @@ export class TileTemplates extends DocumentDirectory { foundry.utils.mergeObject(data, fd.object, { inplace: true }); if (!data.folder) delete data.folder; - let templates = duplicate(this.collection); + let templates = foundry.utils.duplicate(this.collection); if (data.id) { templates.findSplice(t => t._id == data.id, data); } else { data.width = canvas.grid.size; data.height = canvas.grid.size; - let _data = duplicate(data); + let _data = foundry.utils.duplicate(data); let doc = new TileDocument(_data); let template = doc.toObject(); - template._id = template.id = data.id || randomID(); + template._id = template.id = data.id || foundry.utils.randomID(); template.name = data.name; template.visible = true; template.folder = data.folder; @@ -413,7 +413,7 @@ export class TileTemplates extends DocumentDirectory { fc._updateObject = async (event, formData) => { if (!formData.name?.trim()) formData.name = Folder.implementation.defaultName(); let folders = this.folders; - formData._id = randomID(); + formData._id = foundry.utils.randomID(); formData.id = formData._id; formData.visible = true; formData.folder = formData.folder == "" ? null : formData.folder; @@ -511,7 +511,7 @@ export class TileTemplates extends DocumentDirectory { let folder = closestFolder ? this.folders.find(f => f._id == closestFolder.dataset.folderId)?._id : null; // Obtain the dropped Document - const collection = duplicate(this.collection); + const collection = foundry.utils.duplicate(this.collection); let document = data.data; if (!document) document = this.collection.get(data.uuid.replace("Tile.", "")); // Should technically be fromUuid if (!document) return; @@ -553,7 +553,7 @@ export class TileTemplates extends DocumentDirectory { if (data.documentName !== this.constructor.documentName) return; const folder = data.data; - let folders = duplicate(this.folders); + let folders = foundry.utils.duplicate(this.folders); // Determine the closest folder ID const closestFolder = target ? target.closest(".folder") : null; @@ -622,7 +622,7 @@ export class TileTemplates extends DocumentDirectory { } async deleteFolder(folders, folder, options, userId) { - const templates = duplicate(this.collection || []); + const templates = foundry.utils.duplicate(this.collection || []); const parentFolder = folder.folder; const { deleteSubfolders, deleteContents } = options; @@ -659,16 +659,16 @@ export class TileTemplates extends DocumentDirectory { condition: game.user.isGM, callback: header => { const li = header.parent()[0]; - const folders = duplicate(this.folders); + const folders = foundry.utils.duplicate(this.folders); let folder = folders.find(t => t._id == li.dataset.folderId); const options = { top: li.offsetTop, left: window.innerWidth - 310 - FolderConfig.defaultOptions.width }; - let fld = new Folder(mergeObject(folder, { type: "JournalEntry" }, { inplace: false })); + let fld = new Folder(foundry.utils.mergeObject(folder, { type: "JournalEntry" }, { inplace: false })); let config = new FolderConfig(fld, options).render(true); config._updateObject = async (event, formData) => { if (!formData.name?.trim()) formData.name = Folder.implementation.defaultName(); delete formData.type; if (formData.folder == "") formData.folder = null; - folder = mergeObject(folder, formData); + folder = foundry.utils.mergeObject(folder, formData); await game.settings.set("monks-active-tiles", "tile-template-folders", folders); this.render(); } @@ -680,7 +680,7 @@ export class TileTemplates extends DocumentDirectory { condition: game.user.isGM, callback: header => { const li = header.parent()[0]; - const folders = duplicate(this.folders); + const folders = foundry.utils.duplicate(this.folders); const folder = folders.find(t => t._id == li.dataset.folderId); return Dialog.confirm({ title: `${game.i18n.localize("FOLDER.Remove")} ${folder.name}`, @@ -705,7 +705,7 @@ export class TileTemplates extends DocumentDirectory { condition: game.user.isGM, callback: header => { const li = header.parent()[0]; - const folders = duplicate(this.folders); + const folders = foundry.utils.duplicate(this.folders); const folder = folders.find(t => t._id == li.dataset.folderId); return Dialog.confirm({ title: `${game.i18n.localize("FOLDER.Delete")} ${folder.name}`, @@ -737,7 +737,7 @@ export class TileTemplates extends DocumentDirectory { return game.user.isGM && !!document?.folder; }, callback: li => { - const templates = duplicate(this.collection); + const templates = foundry.utils.duplicate(this.collection); const document = templates.find(t => t._id == li.data("documentId")); document.folder = null; game.settings.set("monks-active-tiles", "tile-templates", templates); @@ -748,7 +748,7 @@ export class TileTemplates extends DocumentDirectory { icon: '', condition: () => game.user.isGM, callback: li => { - const templates = duplicate(this.collection); + const templates = foundry.utils.duplicate(this.collection); const id = li.data("documentId"); const document = templates.find(t => t._id == id || (t._id == undefined && id == "")); if (!document) return; @@ -775,7 +775,7 @@ export class TileTemplates extends DocumentDirectory { const templates = this.collection; const document = templates.find(t => t._id == li.data("documentId")); if (!document) return; - const data = deepClone(document); + const data = foundry.utils.deepClone(document); delete data._id; delete data.folder; delete data.sort; @@ -795,7 +795,7 @@ export class TileTemplates extends DocumentDirectory { icon: '', condition: li => game.user.isGM, callback: async (li) => { - const templates = duplicate(this.collection); + const templates = foundry.utils.duplicate(this.collection); const replaceId = li.data("documentId"); const document = templates.find(t => t._id == replaceId); if (!document) return; @@ -834,7 +834,7 @@ export class TileTemplates extends DocumentDirectory { foundry.utils.mergeObject(data, preserve); if (importData instanceof Array) - data._id = randomID(); + data._id = foundry.utils.randomID(); data.visible = true; delete data.img; diff --git a/apps/tile-variables.js b/apps/tile-variables.js index 7da8691..ed1ffea 100644 --- a/apps/tile-variables.js +++ b/apps/tile-variables.js @@ -18,8 +18,8 @@ export class TileVariables extends FormApplication { } getData(options) { - let variables = getProperty(this.object, "flags.monks-active-tiles.variables") || {}; - return mergeObject(super.getData(options), { + let variables = foundry.utils.getProperty(this.object, "flags.monks-active-tiles.variables") || {}; + return foundry.utils.mergeObject(super.getData(options), { variables: variables }); } diff --git a/lang/en.json b/lang/en.json index 8c480e9..b06d81c 100644 --- a/lang/en.json +++ b/lang/en.json @@ -522,6 +522,8 @@ "MonksActiveTiles.drop-macro.hint": "Allow macros dropped on the canvas to be created as Active Tiles", "MonksActiveTiles.tile-edit.name": "Allow Tile Template Editing", "MonksActiveTiles.tile-edit.hint": "Allow editing of Tile Templates, I'd strongly recommend not using this unless you're sure you know what you're doing", + "MonksActiveTiles.show-imageless.name": "Show Imageless Tile", + "MonksActiveTiles.show-imageless.hint": "Show the tile on the token layer to the GM if there's no image set", "MonksActiveTiles.tabs.Setup": "Setup", "MonksActiveTiles.tabs.Actions": "Actions", @@ -534,5 +536,25 @@ "MonksActiveTiles.history.How": "How", "MonksActiveTiles.history.Who": "Who", "MonksActiveTiles.history.Name": "Name", - "MonksActiveTiles.history.Value": "Value" + "MonksActiveTiles.history.Value": "Value", + + "TYPES": { + "RegionBehavior": { + "monks-active-tiles": { + "triggerTile": "Trigger Tile" + } + } + }, + "BEHAVIOR": { + "TYPES": { + "triggerTile": { + "FIELDS": { + "uuid": { + "label": "Tile", + "hint": "Tile to trigger" + } + } + } + } + } } \ No newline at end of file diff --git a/module.json b/module.json index fe47782..5c23992 100644 --- a/module.json +++ b/module.json @@ -1,7 +1,7 @@ { "title": "Monk's Active Tile Triggers", "description": "Want to teleport, or open doors, or hide characters, or display a message, or play a sound, or change a token's elevation when a token walks over a tile... now you can", - "version": "11.27", + "version": "12.01", "authors": [ { "name": "IronMonk", @@ -56,16 +56,21 @@ "css/monks-active-tiles.css" ], "url": "https://github.com/ironmonk88/monks-active-tiles", - "download": "https://github.com/ironmonk88/monks-active-tiles/archive/11.27.zip", + "download": "https://github.com/ironmonk88/monks-active-tiles/archive/12.01.zip", "manifest": "https://github.com/ironmonk88/monks-active-tiles/releases/latest/download/module.json", "bugs": "https://github.com/ironmonk88/monks-active-tiles/issues", "allowBugReporter": true, "id": "monks-active-tiles", "compatibility": { - "minimum": "11", - "verified": "11" + "minimum": "12", + "verified": "12" }, "name": "monks-active-tiles", - "minimumCoreVersion": "11", - "compatibleCoreVersion": "11" + "minimumCoreVersion": "12", + "compatibleCoreVersion": "12", + "documentTypes": { + "RegionBehavior": { + "triggerTile": {} + } + } } \ No newline at end of file diff --git a/monks-active-tiles.js b/monks-active-tiles.js index d0b3dff..eb651f3 100644 --- a/monks-active-tiles.js +++ b/monks-active-tiles.js @@ -50,6 +50,10 @@ export let oldObjectClass = () => { return MonksActiveTiles._oldObjectClass; }; +export let rectContains = (rect, x, y) => { + return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height; +}; + export let patchFunc = (prop, func, type = "WRAPPER") => { let nonLibWrapper = () => { const oldFunc = eval(prop); @@ -213,8 +217,8 @@ export class MonksActiveTiles { let y = ((a * b) / Math.sqrt((a ** 2) + ((b ** 2) / (Math.tan(i) ** 2)))); circlePts.push({ x: x, y: y }); } - circlePts = circlePts.concat(duplicate(circlePts).reverse().map(p => { return { x: -p.x, y: p.y }; })); - circlePts = circlePts.concat(duplicate(circlePts).reverse().map(p => { return { x: p.x, y: -p.y }; })); + circlePts = circlePts.concat(foundry.utils.duplicate(circlePts).reverse().map(p => { return { x: -p.x, y: p.y }; })); + circlePts = circlePts.concat(foundry.utils.duplicate(circlePts).reverse().map(p => { return { x: p.x, y: -p.y }; })); points = MonksActiveTiles.simplify(circlePts.map(p => { return { x: p.x + pos.x, y: p.y + pos.y } }), 40); break; case 'p': //polygon and freehand @@ -313,7 +317,7 @@ export class MonksActiveTiles { token: tokens[0], tile: tile?.toObject(), entity: entity, - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.users.get(userId), players: game.users, value: value, @@ -493,7 +497,7 @@ export class MonksActiveTiles { } static async getEntities(args, defaultType, _entry) { - const { tile, tokens, action, value, userId } = args; + const { tile, tokens, action, value, userId, method } = args; let entities = []; let entry = _entry || action.data?.entity; @@ -541,10 +545,10 @@ export class MonksActiveTiles { else if (id == 'within') { let newEntities = []; if (action.action == "activate") { - newEntities = tile.entitiesWithin(defaultType); + newEntities = tile.entitiesWithin({ collection: defaultType }); } else //find all tokens with this Tile - newEntities = tile.entitiesWithin(); + newEntities = tile.entitiesWithin({useTriggerPt: method != "trigger"}); entities = entities.concat(newEntities); } else if (id == 'controlled') { @@ -701,7 +705,7 @@ export class MonksActiveTiles { static async getLocation(_location, args = {}) { let { value, userId } = args; - let location = duplicate(_location); + let location = foundry.utils.duplicate(_location); if (location.id == 'previous' || location.id == 'current') location = args?.location || value?.location; @@ -891,13 +895,30 @@ export class MonksActiveTiles { } } } else { - name = isEmpty(_location) ? "" : `[${_location.x},${_location.y}${(_location.scale ? `, scale:${_location.scale}` : '')}]`; + name = foundry.utils.isEmpty(_location) ? "" : `[${_location.x},${_location.y}${(_location.scale ? `, scale:${_location.scale}` : '')}]`; } let scene = game.scenes.find(s => s.id == sceneId); return `${(scene?.id != canvas.scene.id ? 'Scene: ' + scene?.name + ', ' : '')}${name}`; } + static getSnappedPosition(x, y, interval = 1) { + if (interval === 0) return { x: Math.round(x), y: Math.round(y) }; + let x0 = x.toNearest(canvas.grid.size); + let y0 = y.toNearest(canvas.grid.size); + let dx = 0; + let dy = 0; + if (interval !== 1) { + let delta = canvas.grid.size / interval; + dx = Math.round((x - x0) / delta) * delta; + dy = Math.round((y - y0) / delta) * delta; + } + return { + x: Math.round(x0 + dx), + y: Math.round(y0 + dy) + }; + } + static testVisibility(point, { tolerance = 2, object = null } = {}) { // If no vision sources are present, the visibility is dependant of the type of user @@ -1024,7 +1045,7 @@ export class MonksActiveTiles { scene: canvas.scene, values: values, value: value, - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, tokens: tokens, method: method, pt: pt, @@ -1063,7 +1084,7 @@ export class MonksActiveTiles { context.args = args; let runasgm = (action.data.runasgm == 'player' || action.data.runasgm == 'gm' ? action.data.runasgm == 'gm' : - (game.modules.get("advanced-macros")?.active || game.modules.get("furnace")?.active ? getProperty(macro, "flags.advanced-macros.runAsGM") || getProperty(macro, "flags.furnace.runAsGM") : true)); + (game.modules.get("advanced-macros")?.active || game.modules.get("furnace")?.active ? foundry.utils.getProperty(macro, "flags.advanced-macros.runAsGM") || getProperty(macro, "flags.furnace.runAsGM") : true)); if (runasgm || userId == game.user.id) { //if (game.modules.get("advanced-macros")?.active || game.modules.get("furnace")?.active) @@ -1092,7 +1113,7 @@ export class MonksActiveTiles { /* if (game.modules.get("advanced-macros")?.active || game.modules.get("furnace")?.active) { - if (getProperty(macro, "flags.advanced-macros.runAsGM") || getProperty(macro, "flags.furnace.runAsGM") || userId == game.user.id) { + if (foundry.utils.getProperty(macro, "flags.advanced-macros.runAsGM") || foundry.utils.getProperty(macro, "flags.furnace.runAsGM") || userId == game.user.id) { //execute the macro if it's set to run as GM or it was the GM that actually moved the token. return await macro.callScriptFunction(context); } else { @@ -1169,7 +1190,7 @@ export class MonksActiveTiles { actor: token?.actor?.toObject(), token: token?.toObject(), tile: tile.toObject(), - variable: getProperty(tile, "flags.monks-active-tiles.variables") || {}, + variable: foundry.utils.getProperty(tile, "flags.monks-active-tiles.variables") || {}, user: game.user, players: game.users, value: value, @@ -1486,7 +1507,7 @@ export class MonksActiveTiles { } if (from) - entity._animationAttributes = mergeObject(entity._animationAttributes || {}, from); + entity._animationAttributes = foundry.utils.mergeObject(entity._animationAttributes || {}, from); let animations = {}; // Define attributes @@ -1519,7 +1540,7 @@ export class MonksActiveTiles { hasAlpha = true; } - if (isEmpty(animations)) + if (foundry.utils.isEmpty(animations)) return; // Dispatch the animation function @@ -1534,7 +1555,7 @@ export class MonksActiveTiles { let realval = attribute.from + attribute.done; if (!isNaN(attribute.done) && attribute.parent[attribute.attribute] != realval) attribute.parent[attribute.attribute] = realval; - setProperty(entity, `_animationAttributes.${attribute.attribute}`, realval) + foundry.utils.setProperty(entity, `_animationAttributes.${attribute.attribute}`, realval) if (attribute.attribute == "alpha" && to.hidden === true && !game.user.isGM && !attribute.parent.visible) attribute.parent.object.visible = true; if (attribute.parent instanceof AmbientLight) { @@ -1653,14 +1674,15 @@ export class MonksActiveTiles { new Promise((resolve) => { resolve(); }); } - let transitionId = randomID(); + let transitionId = foundry.utils.randomID(); t._transition_id = id; t._transition_ready = false; t._transition_time = time; t._transition_to = to; - const container = t._transition = canvas.primary.addChild(new TileMesh(t)); - container.width = entity.width; - container.height = entity.height; + const container = t._transition = new PIXI.Container(); + canvas.tiles.addChild(container); + //container.width = entity.width; + //container.height = entity.height; container.x = entity.x; container.y = entity.y; container.scale.x = 1; @@ -1764,9 +1786,9 @@ export class MonksActiveTiles { } if (transition == "blur") { - fromMesh.filters = [new PIXI.filters.BlurFilter()]; + fromMesh.filters = [new PIXI.BlurFilter()]; fromMesh.filters[0].blur == 0; - toMesh.filters = [new PIXI.filters.BlurFilter()]; + toMesh.filters = [new PIXI.BlurFilter()]; toMesh.filters[0].blur == 200; toMesh.alpha = 0; @@ -1834,7 +1856,7 @@ export class MonksActiveTiles { CanvasAnimation.terminateAnimation(animationName); let result = t._transition_to; let transitionId = t._transition_id; - canvas.primary.removeChild(t._transition); + canvas.tiles.removeChild(t._transition); delete t._transition; delete t._transition_id; delete t._transition_time; @@ -1842,7 +1864,7 @@ export class MonksActiveTiles { t.texture.x = 0; t.texture.y = 0; t.mesh.visible = true; - t.mesh.refresh(); + //t.mesh.refresh(); //log("checking transition queue", t._transition, t._transitionQueue); //if (t._transitionQueue?.length) { // let next = t._transitionQueue.shift(); @@ -2078,9 +2100,9 @@ export class MonksActiveTiles { } } - static canvasClick = function (event, clicktype) { + static selectClick = function (event) { let waitingType = MonksActiveTiles.waitingInput?.waitingfield?.data('type'); - if (clicktype == "click" && (waitingType == 'location' || waitingType == 'either' || waitingType == 'position')) { + if (waitingType == 'location' || waitingType == 'either' || waitingType == 'position') { let restrict = MonksActiveTiles.waitingInput.waitingfield.data('restrict'); if (restrict && !restrict(canvas.scene)) { ui.notifications.error(i18n("MonksActiveTiles.msg.invalid-location")); @@ -2090,7 +2112,11 @@ export class MonksActiveTiles { let update = { x: parseInt(pos.x), y: parseInt(pos.y), sceneId: (canvas.scene.id != MonksActiveTiles.waitingInput.options.parent.object.parent.id ? canvas.scene.id : null) }; ActionConfig.updateSelection.call(MonksActiveTiles.waitingInput, update, event); } + } + static canvasClick = function (event, clicktype) { + if (clicktype == "click") + MonksActiveTiles.selectClick(event); if (canvas.activeLayer instanceof TokenLayer) { //check to see if there are any Tiles that can be activated with a click let pt = canvas.activeLayer.toLocal(event); @@ -2114,6 +2140,92 @@ export class MonksActiveTiles { }); } catch { } + CONFIG.RegionBehavior.typeIcons["monks-active-tiles.triggerTile"] = "fa-solid fa-cubes"; + + class ActiveTileDocumentUUIDField extends foundry.data.fields.DocumentUUIDField { + _toInput(config) { + Object.assign(config, { type: this.type, single: this.single }); + return foundry.applications.elements.HTMLDocumentTagsElement.create(config); + } + } + class TriggerTileRegionBehavior extends foundry.data.regionBehaviors.RegionBehaviorType { + static defineSchema() { + return { + events: this._createEventsField(), + uuid: new ActiveTileDocumentUUIDField({ + type: "Tile", + single: false, + label: "BEHAVIOR.TYPES.triggerTile.FIELDS.uuid.label", + hint: "BEHAVIOR.TYPES.triggerTile.FIELDS.uuid.hint" + }) + } + } + async _handleRegionEvent(event) { + if (!this.uuid) return; + const doc = await fromUuid(this.uuid); + if (!(doc instanceof TileDocument)) { + console.error(`${this.uuid} does not exist`); + return; + } + let triggerData = foundry.utils.getProperty(doc, "flags.monks-active-tiles"); + if (triggerData?.active) { + if (setting("prevent-when-paused") && game.paused && !game.user.isGM && triggerData.allowpaused !== true) + return; + + //check to see if this trigger is restricted by control type + if ((triggerData.controlled == 'gm' && !game.user.isGM) || (triggerData.controlled == 'player' && game.user.isGM)) + return; + + let tokens = canvas.tokens.controlled.map(t => t.document); + //check to see if this trigger is per token, and already triggered + if (triggerData.pertoken) { + tokens = tokens.filter(t => !doc.hasTriggered(t.id)); //.uuid + if (tokens.length == 0) + return; + } + + let result = await doc.trigger({ tokens: tokens, method: 'region', options: { value: { region: this.region } } }) || {}; + //foundry.utils.mergeObject(results, result); + //if (result?.stoptriggers) + // break; + } + } + } + Object.assign(CONFIG.RegionBehavior.dataModels, { + "monks-active-tiles.triggerTile": TriggerTileRegionBehavior, + }); + + patchFunc("TextEditor.prototype.constructor.truncateText", function (wrapped, ...args) { + let [text, options] = args; + if (text == undefined) { + args[0] = ""; + } + return wrapped(...args); + }); + + patchFunc("foundry.applications.elements.HTMLStringTagsElement.prototype.constructor.renderTag", function (wrapped, ...args) { + let [tag, label] = args; + if (tag.includes(".Tile.") && !label) { + try { + let document = fromUuidSync(tag); + if (document) { + if (game.modules.get('tagger')?.active) { + let tags = Tagger.getTags(document); + if (tags.length) + name = tags[0]; + } + + if (!name) + name = document.documentName + ": " + document.id; + + args[1] = name; + } + } catch { } + } + return wrapped(...args); + }, "MIXED"); + + //@Tile[Scene.b77ocyto1VdgAZU5.Tile.QW3oZo39pZsf8cTX landing:test1]{Journal Click Tile} CONFIG.TextEditor.enrichers.push({ id: 'MonksActiveTileTrigger', pattern: new RegExp(`@(Tile)\\[([^\\]]+)\\](?:{([^}]+)})?`, 'g'), enricher: MonksActiveTiles._createTileLink }); @@ -2263,7 +2375,7 @@ export class MonksActiveTiles { tileData.x = tileData.x - (tileData.width / 2); tileData.y = tileData.y - (tileData.height / 2); if (!event.shiftKey) { - const { x, y } = canvas.grid.getSnappedPosition(tileData.x, tileData.y); + const { x, y } = MonksActiveTiles.getSnappedPosition(tileData.x, tileData.y); tileData.x = x; tileData.y = y; } @@ -2287,8 +2399,8 @@ export class MonksActiveTiles { let tileCreatePreview = function (wrapped, ...args) { let data = args[0]; - if (getProperty(data, "flags.monks-active-tiles") == undefined) { - data = mergeObject(data, { + if (foundry.utils.getProperty(data, "flags.monks-active-tiles") == undefined) { + data = foundry.utils.mergeObject(data, { flags: { 'monks-active-tiles': { active: true, @@ -2478,7 +2590,7 @@ export class MonksActiveTiles { let results = {}; for (let doc of docs) { if (!doc) continue; - let triggerData = getProperty(doc, "flags.monks-active-tiles"); + let triggerData = foundry.utils.getProperty(doc, "flags.monks-active-tiles"); if (triggerData?.active) { if (setting("prevent-when-paused") && game.paused && !game.user.isGM && triggerData.allowpaused !== true) return; @@ -2496,7 +2608,7 @@ export class MonksActiveTiles { } let result = await doc.trigger({ tokens: tokens, method: 'door', options: { value: { walls: walls }, change: wall._wallchange || "checklock" } }) || {}; - mergeObject(results, result); + foundry.utils.mergeObject(results, result); if (result?.stoptriggers) break; } @@ -2601,7 +2713,7 @@ export class MonksActiveTiles { if (!lastPositionContainsTile && currentPositionContainsTile && !MonksActiveTiles.hoveredTiles.has(tile)) { if (game.user.isGM || !canvas?.scene?.tokenVision || !triggerData.vision || (!tile.hidden && entities.some(t => { - return canvas.effects.visibility.testVisibility({ x: tile.x, y: tile.y }, { tolerance: 1, object: t }); + return canvas.visibility.testVisibility({ x: tile.x, y: tile.y }, { tolerance: 1, object: t }); }))) { MonksActiveTiles.hoveredTiles.add(tile); if (triggerData.pointer) { @@ -2624,7 +2736,7 @@ export class MonksActiveTiles { if (setting("prevent-when-paused") && game.paused && !game.user.isGM && triggerData.allowpaused !== true) continue; if (game.user.isGM || !canvas?.scene?.tokenVision || !triggerData.vision || (!tile.hidden && entities.some(t => { - return canvas.effects.visibility.testVisibility({ x: tile.x, y: tile.y }, { tolerance: 1, object: t }); + return canvas.visibility.testVisibility({ x: tile.x, y: tile.y }, { tolerance: 1, object: t }); }))) { tile.trigger({ tokens: tokens, method: 'hoverout', pt: currentPosition }); } @@ -2635,6 +2747,12 @@ export class MonksActiveTiles { lastPosition = currentPosition; }); + let _onSelectClick = function (wrapped, ...args) { + let event = args[0]; + MonksActiveTiles.selectClick.call(this, event, 'click'); + return wrapped(...args); + } + let _onLeftClick = function (wrapped, ...args) { let event = args[0]; MonksActiveTiles.canvasClick.call(this, event, 'click'); @@ -2663,10 +2781,26 @@ export class MonksActiveTiles { wrapped(...args); } - patchFunc("Canvas.prototype._onClickLeft", _onLeftClick, "MIXED"); - patchFunc("Canvas.prototype._onClickRight", _onRightClick, "MIXED"); - patchFunc("Canvas.prototype._onClickLeft2", _onLeftClick2, "MIXED"); - patchFunc("Canvas.prototype._onClickRight2", _onRightClick2, "MIXED"); + patchFunc("TokenLayer.prototype._onClickLeft", _onLeftClick); + patchFunc("TokenLayer.prototype._onClickRight", _onRightClick); + patchFunc("TokenLayer.prototype._onClickLeft2", _onLeftClick2); + patchFunc("TokenLayer.prototype._onClickRight2", _onRightClick2); + + for (let layer of ["TilesLayer", "DrawingsLayer", "WallsLayer", "LightingLayer", "SoundsLayer", "RegionLayer", "NotesLayer"]) { + patchFunc(`${layer}.prototype._onClickLeft`, _onLeftClick, "MIXED"); + } + + patchFunc("TilesLayer.prototype._deactivate", function (wrapper, ...args) { + wrapper(...args); + const showImageless = setting("show-imageless") && game.user.isGM; + this.objects.visible = showImageless; + }) + + patchFunc("TilesLayer.prototype._draw", async function (wrapper, ...args) { + await wrapper(...args); + const showImageless = setting("show-imageless") && game.user.isGM; + this.objects.visible ||= showImageless; + }) let clickDocumentName = async function (wrapped, ...args) { let event = args[0]; @@ -2826,7 +2960,7 @@ export class MonksActiveTiles { // Commit the movement and update the final resolved destination coordinates let animate = true; - priorDest = duplicate(path.B); + priorDest = foundry.utils.duplicate(path.B); await token.document.update(path.B, { animate: animate }); path.B.x = token.x; path.B.y = token.y; @@ -2863,7 +2997,7 @@ export class MonksActiveTiles { for (let tile of _tiles) { let triggerData = tile.flags["monks-active-tiles"]; if (triggerData && triggerData.actions?.length > 0) { - let actions = duplicate(triggerData.actions); + let actions = foundry.utils.duplicate(triggerData.actions); let update = false; for (let i = 0; i < actions.length; i++) { let action = actions[i]; @@ -3271,7 +3405,7 @@ export class MonksActiveTiles { let tile = (data?.tileid ? await fromUuid(data.tileid) : null); let token = (data?.tokenid ? await fromUuid(data.tokenid) : null); - let options = mergeObject(data, {tile, token}); + let options = foundry.utils.mergeObject(data, {tile, token}); MonksActiveTiles._showDialog(options).then((results) => { MonksActiveTiles.emit("returndialog", { _id: data._id, tileid: data?.tileid, results: results }); @@ -3331,17 +3465,17 @@ export class MonksActiveTiles { } catch {} } - let volume = Math.clamped(data.volume, 0, 1); + let volume = Math.clamp(data.volume, 0, 1); debug('Playing', data.src); if (data.src) { - AudioHelper.play({ src: data.src, volume: (data.fade > 0 ? 0 : volume), loop: data.loop }, false).then((sound) => { + foundry.audio.AudioHelper.play({ src: data.src, volume: (data.fade > 0 ? 0 : volume), loop: data.loop }, false).then((sound) => { if (data.fade > 0) sound.fade(volume * getVolume(), { duration: data.fade * 1000 }); if (tile.soundeffect == undefined) tile.soundeffect = {}; tile.soundeffect[data.actionid] = sound; - tile.soundeffect[data.actionid].on("end", () => { + tile.soundeffect[data.actionid].addEventListener("end", () => { debug('Finished playing', data.src); delete tile.soundeffect[data.actionid]; }); @@ -3428,8 +3562,8 @@ export class MonksActiveTiles { return ui.notifications.warn(`You do not have permission to view ${entity.name}.`); let checkEntity = entity.parent || entity; - if (game.modules.get("monks-enhanced-journal")?.active && checkEntity instanceof JournalEntry && checkEntity.pages.size == 1 && !!getProperty(checkEntity.pages.contents[0], "flags.monks-enhanced-journal.type")) { - let type = getProperty(checkEntity.pages.contents[0], "flags.monks-enhanced-journal.type"); + if (game.modules.get("monks-enhanced-journal")?.active && checkEntity instanceof JournalEntry && checkEntity.pages.size == 1 && !!foundry.utils.getProperty(checkEntity.pages.contents[0], "flags.monks-enhanced-journal.type")) { + let type = foundry.utils.getProperty(checkEntity.pages.contents[0], "flags.monks-enhanced-journal.type"); if (type == "base" || type == "oldentry") type = "journalentry"; let types = game.MonksEnhancedJournal.getDocumentTypes(); if (types[type]) { @@ -3648,7 +3782,7 @@ export class MonksActiveTiles { let canView = game.user.isGM; if (!canView) { let token = canvas.tokens.controlled[0]; - canView = !entity.hidden && entity.parent.id == canvas.scene.id && (!canvas.scene.tokenVision || (token && canvas.effects.visibility.testVisibility({ x: token.x, y: token.y }, { tolerance: 1, object: entity }))); + canView = !entity.hidden && entity.parent.id == canvas.scene.id && (!canvas.scene.tokenVision || (token && canvas.visibility.testVisibility({ x: token.x, y: token.y }, { tolerance: 1, object: entity }))); } if (canView) MonksActiveTiles.transitionImage(entity, data.transitionId, data.from, data.img, data.transition, data.time); @@ -3770,7 +3904,7 @@ export class MonksActiveTiles { return tile.checkClick(pt, clicktype, event); }).filter(t => !!t) .sort((a, b) => { - return b.tile.z - a.tile.z; + return (b.tile.sort ?? b.tile.z) - (a.tile.sort ?? a.tile.z); }); for (let t of tiles) { let triggerResult = await t.tile.trigger(t.args); @@ -3946,11 +4080,13 @@ export class MonksActiveTiles { console.warn("tokensWithin is deprecated and will be remove in later version. Please use entitiesWithin instead"); return this.entitiesWithin(); } - TileDocument.prototype.entitiesWithin = function (collection = "tokens") { + TileDocument.prototype.entitiesWithin = function ({ collection = "tokens", useTriggerPt = true }) { return this.parent[collection]?.filter(t => { if (t.id == this.id) return false; - let midEntity = getProperty(t, "flags.monks-active-tiles.triggerPt"); + let midEntity; + if (useTriggerPt) + midEntity = foundry.utils.getProperty(t, "flags.monks-active-tiles.triggerPt"); if (midEntity == undefined) { midEntity = { x: t.x, y: t.y }; if (t instanceof TokenDocument) { @@ -4418,7 +4554,7 @@ export class MonksActiveTiles { //check to see if the clicked point is within the Tile if (pt == undefined || this.pointWithin(pt)) { if (game.user.isGM || !canvas?.scene?.tokenVision || !triggerData.vision || (entities.some(t => { - return canvas.effects.visibility.testVisibility({ x: this.x, y: this.y }, { tolerance: 1, object: t }); + return canvas.visibility.testVisibility({ x: this.x, y: this.y }, { tolerance: 1, object: t }); }))) { return { tile: this, args: { tokens: tokens, method: clicktype, pt: pt, options: { event: event } } }; } @@ -4630,7 +4766,7 @@ export class MonksActiveTiles { }*/ TileDocument.prototype.checkStop = function () { - let triggers = MonksActiveTiles.getTrigger(getProperty(this, "flags.monks-active-tiles.trigger")); + let triggers = MonksActiveTiles.getTrigger(foundry.utils.getProperty(this, "flags.monks-active-tiles.trigger")); //if (triggers.includes('movement')) // return false; let hasLanding = false; @@ -4668,14 +4804,16 @@ export class MonksActiveTiles { if (triggerData.minrequired && this.countTriggered() < triggerData.minrequired) return; - for (let tkn of tokens) { - setProperty(tkn, "flags.monks-active-tiles.triggerPt", pt); + if (method != "trigger") { + for (let tkn of tokens) { + foundry.utils.setProperty(tkn, "flags.monks-active-tiles.triggerPt", pt); + } } //A token has triggered this tile, what actions do we need to do let values = []; let value = { tokens: tokens }; - let context = mergeObject({ + let context = foundry.utils.mergeObject({ tile: this, tokens: tokens, userId: userId, @@ -4776,7 +4914,7 @@ export class MonksActiveTiles { let actionResult = await this.runActions(context, Math.max(start, 0), null); for (let tkn of tokens) { - setProperty(tkn, "flags.monks-active-tiles.triggerPt", null); + foundry.utils.setProperty(tkn, "flags.monks-active-tiles.triggerPt", null); } return actionResult; @@ -4832,14 +4970,14 @@ export class MonksActiveTiles { if (Array.isArray(result)) { for (let res of result) { if (typeof res == 'object') { - context.value = mergeObject(context.value, res); + context.value = foundry.utils.mergeObject(context.value, res); } } } else { - context.value = mergeObject(context.value, result); + context.value = foundry.utils.mergeObject(context.value, result); } delete context.value.goto; - context.values.push(mergeObject(result, { action: action })); + context.values.push(foundry.utils.mergeObject(result, { action: action })); context.stopmovement = context.stopmovement || result.stopmovement; if (!!context.stopmovement && context.stopdata?.callback) { context.stopdata.stopmovement = context.stopmovement; @@ -4919,8 +5057,8 @@ export class MonksActiveTiles { result = result.continue; } let cancontinue = await Hooks.call("triggerTile", this, this, context.tokens, context.action, context.userId, context.value); - if (getProperty(this, "flags.monks-active-tiles.allowdisabled") != undefined) { - context.value.allowdisabled = getProperty(this, "flags.monks-active-tiles.allowdisabled"); + if (foundry.utils.getProperty(this, "flags.monks-active-tiles.allowdisabled") != undefined) { + context.value.allowdisabled = foundry.utils.getProperty(this, "flags.monks-active-tiles.allowdisabled"); this.unsetFlag("monks-active-tiles", "allowdisabled"); } if (result === false || cancontinue === false || (this.getFlag('monks-active-tiles', 'active') === false && context.value.allowdisabled !== true) || this.getFlag('monks-active-tiles', 'continue') === false) { @@ -5007,10 +5145,10 @@ export class MonksActiveTiles { else tileHistory[tokenid].triggered.push(data); - //this.flags = mergeObject(this.flags, { "monks-active-tiles.history": tileHistory }); //Due to a race condition we need to set the actual value before trying to save it + //this.flags = foundry.utils.mergeObject(this.flags, { "monks-active-tiles.history": tileHistory }); //Due to a race condition we need to set the actual value before trying to save it try { - await this.setFlag("monks-active-tiles", "history", duplicate(this.flags["monks-active-tiles"]?.history || tileHistory)); + await this.setFlag("monks-active-tiles", "history", foundry.utils.duplicate(this.flags["monks-active-tiles"]?.history || tileHistory)); canvas.perception.update({ refreshLighting: true, refreshSounds: true, @@ -5022,11 +5160,11 @@ export class MonksActiveTiles { } TileDocument.prototype.removeHistory = async function (id) { - let tileHistory = duplicate(this.flags["monks-active-tiles"]?.history || {}); + let tileHistory = foundry.utils.duplicate(this.flags["monks-active-tiles"]?.history || {}); for (let [k, v] of Object.entries(tileHistory)) { let item = v.triggered.findSplice(h => h.id == id); if (item != undefined) { - this.flags = mergeObject(this.flags, { "monks-active-tiles.history": tileHistory }); //Due to a race condition we need to set the actual value before trying to save it + this.flags = foundry.utils.mergeObject(this.flags, { "monks-active-tiles.history": tileHistory }); //Due to a race condition we need to set the actual value before trying to save it await this.setFlag("monks-active-tiles", "history", tileHistory); break; } @@ -5034,7 +5172,7 @@ export class MonksActiveTiles { } TileDocument.prototype.resetHistory = async function (tokenid) { - //let tileHistory = duplicate(this.flags["monks-active-tiles"]?.history || {}); + //let tileHistory = foundry.utils.duplicate(this.flags["monks-active-tiles"]?.history || {}); if (tokenid == undefined) { this.flags["monks-active-tiles"].history = {}; await this.update({ [`flags.monks-active-tiles.-=history`]: null }, { render: false }); @@ -5074,7 +5212,7 @@ export class MonksActiveTiles { }); let user = game.users.find(p => p.id == data.who); - stats.list.push(mergeObject(data, { + stats.list.push(foundry.utils.mergeObject(data, { tokenid: k, name: token?.name || (k == "" ? "" : 'Unknown'), username: user?.name || 'Unknown', @@ -5084,9 +5222,9 @@ export class MonksActiveTiles { } if (tknstat.first && (stats.first == undefined || tknstat.first.when < stats.first.when)) - stats.first = mergeObject(tknstat.first, { tokenid: k }); + stats.first = foundry.utils.mergeObject(tknstat.first, { tokenid: k }); if (tknstat.last && (stats.last == undefined || tknstat.last.when > stats.last.when)) - stats.last = mergeObject(tknstat.last, { tokenid: k }); + stats.last = foundry.utils.mergeObject(tknstat.last, { tokenid: k }); stats.count += tknstat.count; } @@ -5207,7 +5345,7 @@ export class MonksActiveTiles { let templates = setting("tile-templates") || []; let data = this.object.toObject(); - data._id = data.id = randomID(); + data._id = data.id = foundry.utils.randomID(); data.name = fd.object.name; data.visible = true; delete data.img; @@ -5244,10 +5382,10 @@ export class MonksActiveTiles { let document = data.document; let endPt = data.pt; if (data.stopmovement == "snap") { - let snapPoint = { B: duplicate(endPt) }; + let snapPoint = { B: foundry.utils.duplicate(endPt) }; if (endPt.x != data.dest.x || endPt.y != data.dest.y) snapPoint = Ray.towardsPoint(endPt, data.dest, document.parent.dimensions.size / 3); - endPt = canvas.grid.getSnappedPosition(snapPoint.B.x, snapPoint.B.y); + endPt = MonksActiveTiles.getSnappedPosition(snapPoint.B.x, snapPoint.B.y); if (isNaN(endPt.x)) endPt.x = data.pt.x; if (isNaN(endPt.y)) endPt.y = data.pt.y; log("Snapping to", endPt); @@ -5279,7 +5417,7 @@ export class MonksActiveTiles { for (let triggerObject of triggeringList) { triggerObject.tile = await fromUuid(triggerObject.tileId); - if (!getProperty(triggerObject.tile, "flags.monks-active-tiles.active") || triggerObject.stop) + if (!foundry.utils.getProperty(triggerObject.tile, "flags.monks-active-tiles.active") || triggerObject.stop) continue; triggerObject.document = await fromUuid(triggerObject.documentId); @@ -5292,7 +5430,7 @@ export class MonksActiveTiles { for (let i = 0; i < triggers.length; i++) { let trigger = triggers[i]; //log('Tile is triggering', when, document); - if (getProperty(trigger.tile, "flags.monks-active-tiles.active") && !trigger.stop) { + if (foundry.utils.getProperty(trigger.tile, "flags.monks-active-tiles.active") && !trigger.stop) { trigger.args.stopdata = { tile: trigger.tile, document: trigger.document, @@ -5353,6 +5491,12 @@ Hooks.on('ready', () => { MonksActiveTiles._oldSheetClass = CONFIG.Tile.sheetClasses.base['core.TileConfig'].cls; CONFIG.Tile.sheetClasses.base['core.TileConfig'].cls = WithActiveTileConfig(CONFIG.Tile.sheetClasses.base['core.TileConfig'].cls); + Object.defineProperty(CONFIG.Tile.documentClass.prototype, "name", { + get: function () { + return this.getFlag("monks-active-tiles", "name"); + } + }); + if (game.modules.get("item-piles")?.active && setting('drop-item')) { game.settings.set('monks-active-tiles', 'drop-item', false); ui.notifications.warn(i18n("MonksActiveTiles.msg.itempiles")); @@ -5429,7 +5573,7 @@ Hooks.on('ready', () => { Hooks.on('createToken', async (document, options, userId) => { let tiles = document.parent.tiles.map((tile) => { - let triggerData = getProperty(tile, "flags.monks-active-tiles") || {}; + let triggerData = foundry.utils.getProperty(tile, "flags.monks-active-tiles") || {}; let triggers = MonksActiveTiles.getTrigger(triggerData?.trigger); if (triggerData?.active && triggerData.actions?.length > 0 && triggers.includes('create')) { let token = document.object; @@ -5444,7 +5588,7 @@ Hooks.on('createToken', async (document, options, userId) => { } } return null; - }).filter(t => !!t).sort((a, b) => b.tile.z - a.tile.z); + }).filter(t => !!t).sort((a, b) => (b.tile.sort ?? b.tile.z) - (a.tile.sort ?? a.tile.z)); for (let t of tiles) { let triggerResult = await t.tile.trigger(t.args); if (triggerResult?.stoptriggers) @@ -5467,7 +5611,7 @@ Hooks.once('ready', () => { //make sure to bypass if the token is being dropped somewhere, otherwise we could end up triggering a lot of tiles - if ((update.x != undefined || update.y != undefined || update.elevation != undefined || update.rotation != undefined) && options.bypass !== true && (options.animate !== false || options.teleport)) { //(!game.modules.get("drag-ruler")?.active || options.animate)) { + if (((update.x != undefined && update.x != document.x) || (update.y != undefined && update.y != document.y) || update.elevation != undefined || update.rotation != undefined) && options.bypass !== true && (options.animate !== false || options.teleport)) { //(!game.modules.get("drag-ruler")?.active || options.animate)) { let token = document.object; if ((document.caught || document.getFlag('monks-active-tiles', 'teleporting')) && !options.teleport) { @@ -5599,11 +5743,11 @@ Hooks.once('ready', () => { let dist = Math.hypot(triggerPt.x - tokenPos.x, triggerPt.y - tokenPos.y); let triggerObject = { - id: randomID(), + id: foundry.utils.randomID(), tileId: tile.uuid, documentId: document.uuid, when, - zIndex: tile.z, + zIndex: tile.sort ?? tile.z, dist, end: { x: triggerPt.x - tokenMidX, y: triggerPt.y - tokenMidY }, dest, @@ -5657,7 +5801,7 @@ Hooks.on("preUpdateCombat", async function (combat, delta) { return { tile, args: { tokens: tokens, method: 'turnend', options: { turn: delta.turn } } }; } return null; - }).filter(t => !!t).sort((a, b) => b.tile.z - a.tile.z); + }).filter(t => !!t).sort((a, b) => (b.tile.sort ?? b.tile.z) - (a.tile.sort ?? a.tile.z)); for (let t of tiles) { let triggerResult = await t.tile.trigger(t.args); if (triggerResult?.stoptriggers) @@ -5686,7 +5830,7 @@ Hooks.on("updateCombat", async function (combat, delta) { } } return null; - }).filter(t => !!t).sort((a, b) => b.tile.z - a.tile.z); + }).filter(t => !!t).sort((a, b) => (b.tile.sort ?? b.tile.z) - (a.tile.sort ?? a.tile.z)); for (let t of tiles) { let triggerResult = await t.tile.trigger(t.args); if (triggerResult?.stoptriggers) @@ -5704,7 +5848,7 @@ Hooks.on("deleteCombat", async function (combat, delta) { let tokens = combat.combatants.map(c => c.token); return { tile, args: { tokens: tokens, method: 'combatend' } }; } - }).filter(t => !!t).sort((a, b) => b.tile.z - a.tile.z); + }).filter(t => !!t).sort((a, b) => (b.tile.sort ?? b.tile.z) - (a.tile.sort ?? a.tile.z)); for (let t of tiles) { let triggerResult = await t.tile.trigger(t.args); if (triggerResult?.stoptriggers) @@ -5715,7 +5859,7 @@ Hooks.on("deleteCombat", async function (combat, delta) { Hooks.on('preCreateChatMessage', async (document, data, options, userId) => { if (document.getFlag('monks-active-tiles', 'language')) { - setProperty(data, "flags.polyglot.language", document.getFlag('monks-active-tiles', 'language')); + foundry.utils.setProperty(data, "flags.polyglot.language", document.getFlag('monks-active-tiles', 'language')); //document.update({ "flags.polyglot.language": document.getFlag('monks-active-tiles', 'language') }); } }); @@ -5794,7 +5938,7 @@ Hooks.on("renderWallConfig", async (app, html, options) => { let tilename = ""; if (entity.id) tilename = entity.id == "within" ? i18n("MonksActiveTiles.WithinWall") : await MonksActiveTiles.entityName(entity); - let triggerData = mergeObject({ tilename: tilename, showtagger: game.modules.get('tagger')?.active }, (app.object.flags['monks-active-tiles'] || {})); + let triggerData = foundry.utils.mergeObject({ tilename: tilename, showtagger: game.modules.get('tagger')?.active }, (app.object.flags['monks-active-tiles'] || {})); triggerData.entity = JSON.stringify(entity); let wallHtml = await renderTemplate("modules/monks-active-tiles/templates/wall-config.html", triggerData); @@ -5849,7 +5993,7 @@ Hooks.on("dropCanvasData", async (canvas, data, options, test) => { let size = canvas.scene.dimensions.size * setting("drop-item-size"); let dest = { x: data.x - (size / 2), y: data.y - (size / 2) }; - let td = mergeObject(dest, { + let td = foundry.utils.mergeObject(dest, { img: item.img, width: size, height: size, @@ -5888,7 +6032,7 @@ Hooks.on("dropCanvasData", async (canvas, data, options, test) => { let size = canvas.scene.dimensions.size; let dest = { x: data.x - (size / 2), y: data.y - (size / 2) }; - let td = mergeObject(dest, { + let td = foundry.utils.mergeObject(dest, { img: scene.background?.src, width: size, height: size, @@ -5917,7 +6061,7 @@ Hooks.on("dropCanvasData", async (canvas, data, options, test) => { let size = canvas.scene.dimensions.size; let dest = { x: data.x - (size / 2), y: data.y - (size / 2) }; - let td = mergeObject(dest, { + let td = foundry.utils.mergeObject(dest, { img: macro.img || "icons/svg/dice-target.svg", width: size, height: size, @@ -5951,6 +6095,18 @@ Hooks.on("renderTileConfig", (app, html, data) => { if ($("save-template-button", html).length == 0) $("