diff --git a/eslint.config.mjs b/eslint.config.mjs index 7e6b14a..6041cd4 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -13,11 +13,13 @@ export default [ globals: { ...globals.browser, ActiveEffect: false, + canvas: false, ChatMessage: false, ColorAdjustmentsSamplerShader: false, CONFIG: false, deepClone: false, foundry: false, + fromUuid: false, game: false, Hooks: false, randomID: false, diff --git a/scripts/allPowers.js b/scripts/allPowers.js index 07cb6ca..b95a1d1 100644 --- a/scripts/allPowers.js +++ b/scripts/allPowers.js @@ -1,4 +1,6 @@ -import { moduleName, log } from './globals.js' +import { moduleName } from './globals.js' + +const MAINTAIN_ICON = 'icons/magic/symbols/runes-star-blue.webp' class PowerEffect { constructor (token, targets) { @@ -26,7 +28,9 @@ class PowerEffect { createEffectDocument (icon, name, changes = null) { if (changes === null) { - changes = [] + changes = [ + { key: 'flags.swade-mb-helpers.hasPower', value: 1, + priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE } ] } return { icon, @@ -46,6 +50,21 @@ class PowerEffect { } } + async applyActiveEffects (token, effectDocuments) { + const mutation = { + embedded: { ActiveEffect: {} } + } + const mutateOptions = { + permanent: true, + description: `${this.source.name} applying ${effectDocuments[effectDocuments.length - 1]?.name} to ${token.name}` + + } + for (const effectDocument of effectDocuments) { + mutation.embedded.ActiveEffect[effectDocument.name] = effectDocument + } + await warpgate.mutate(token.document, mutation, {}, mutateOptions) + } + get name () { return 'Unknown Power' } get icon () { return 'icons/magic/symbols/question-stone-yellow.webp' } get duration () { return 5 } @@ -57,7 +76,7 @@ class PowerEffect { { name: 'Glow', id: 'glow', value: 1, - advanced: false, + epic: false, effect: true, icon: 'icons/magic/light/orb-shadow-blue.webp', changes: [ { key: '@Skill{Stealth}[system.die.modifier]', value: -2, @@ -66,7 +85,7 @@ class PowerEffect { { name: 'Shroud', id: 'shroud', value: 1, - advanced: false, + epic: false, effect: true, icon: 'icons/magic/perception/shadow-stealth-eyes-purple.webp', changes: [ { key: '@Skill{Stealth}[system.die.modifier]', value: 1, @@ -75,7 +94,7 @@ class PowerEffect { { name: 'Hinder', id: 'hinder', value: 1, - advanced: false, + epic: false, effect: true, icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp', changes: [ { key: 'system.stats.speed.value', value: -2, @@ -84,7 +103,7 @@ class PowerEffect { { name: 'Hurry', id: 'hurry', value: 1, - advanced: false, + epic: false, effect: true, icon: 'icons/skills/movement/feet-winged-sandals-tan.webp', changes: [ { key: 'system.stats.speed.value', value: 2, @@ -115,7 +134,7 @@ class PowerEffect { data.push({ type: 'checkbox', label: ( - `${mod.advanced ? '⭐ ' : ''}${mod.name} ` + + `${mod.epic ? '⭐ ' : ''}${mod.name} ` + `(${mod.value >= 0 ? '+' : ''}${mod.value})` ), }) @@ -168,7 +187,7 @@ class PowerEffect { } } - async createSecondaryEffects () { + async createSecondaryEffects (maintId) { const docs = [] for (const mod of this.modifiers) { if (this.data.mods.has(mod.id) && mod.effect) { @@ -178,6 +197,9 @@ class PowerEffect { // turn doc.duration.rounds = 1 doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.StartOfTurnAuto + } else { + doc.duration.seconds = 594 + doc.flags[moduleName].maintId = maintId } docs.push(doc) } @@ -185,48 +207,51 @@ class PowerEffect { return docs } - async createPrimaryEffect () { + async createPrimaryEffect (maintId) { const doc = this.createEffectDocument(this.icon, this.name, []) + doc.flags[moduleName].maintId = maintId + doc.duration.seconds = 594 return doc } - async createMaintainEffect () { + async createMaintainEffect (maintId) { const doc = this.createEffectDocument( - this.icon, `Maintaining ${this.name}`, []) + MAINTAIN_ICON, `Maintaining ${this.name}`, []) doc.duration.rounds = this.duration doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.StartOfTurnPrompt doc.flags.swade.loseTurnOnHold = true + doc.flags[moduleName].maintainingId = maintId + doc.flags[moduleName].targetIds = this.targets.map(t => t.id) return doc } + // eslint-disable-next-line no-unused-vars async secondaryDocsForTarget(docs, target) { return deepClone(docs) } - async primaryDocForTarget(doc, ids, target) { + // eslint-disable-next-line no-unused-vars + async primaryDocForTarget(doc, target) { const newDoc = deepClone(doc) - newDoc.flags[moduleName].secondaryDocIds = deepClone(ids) return newDoc } async apply () { - const secondaryDocs = await this.createSecondaryEffects() - const primaryDoc = await this.createPrimaryEffect() - const maintainDoc = await this.createMaintainEffect() - const primaryIds = [] + const maintId = randomID() + const secondaryDocs = await this.createSecondaryEffects(maintId) + const primaryDoc = await this.createPrimaryEffect(maintId) + const maintainDoc = await this.createMaintainEffect(maintId) for (const target of this.targets) { - const created = await target.actor.createEmbeddedDocuments( - 'ActiveEffect', await this.secondaryDocsForTarget(secondaryDocs, target)) - const createdIds = created.map(c => c.uuid) + const targetDocs = await this.secondaryDocsForTarget(secondaryDocs, target) if (this.duration > 0 || this.usePrimaryEffect) { - const pCreated = await target.actor.createEmbeddedDocuments( - 'ActiveEffect', [await this.primaryDocForTarget(primaryDoc, createdIds, target)]) - primaryIds.push(pCreated[0].uuid) + targetDocs.push(await this.primaryDocForTarget(primaryDoc, target)) + } + if (targetDocs.length > 0) { + await this.applyActiveEffects(target, targetDocs) } } if (this.duration > 0) { - maintainDoc.flags[moduleName].secondaryDocIds = deepClone(primaryIds) - await this.source.actor.createEmbeddedDocuments('ActiveEffect', [maintainDoc]) + await this.applyActiveEffects(this.source, [maintainDoc]) } } diff --git a/scripts/powers.js b/scripts/powers.js index 68b2bec..4113b30 100644 --- a/scripts/powers.js +++ b/scripts/powers.js @@ -1,12 +1,37 @@ -import { log, moduleName } from './globals.js' +import { moduleName } from './globals.js' import { PowerClasses } from './allPowers.js' export async function powerEffectManagementHook(effect, data, userId) { - log('ids:', effect.getFlag(moduleName, 'secondaryDocIds')) - log('Power Effect Management') - log('effect:', effect) - log('data:', data) - log('userId:', userId) + if (game.user.id !== userId) { + return + } + const maintId = effect.getFlag(moduleName, 'maintainingId') + if (!maintId) { + return + } + const mutateOptions = { + permanent: true, + comparisonKeys: { + ActiveEffect: 'id' + } + } + const targetIds = effect.getFlag(moduleName, 'targetIds') || [] + for (const targetId of targetIds) { + const mutation = { + embedded: { ActiveEffect: {} } + } + const target = canvas.tokens.get(targetId) + if (!target) { + continue + } + const effects = target.actor.effects.filter( + e => e.getFlag(moduleName, 'maintId') === maintId) + for (const effect of effects) { + mutation.embedded.ActiveEffect[effect.id] = warpgate.CONST.DELETE + } + mutateOptions.description = `${effect.parent.name} is no longer ${effect.name} on ${target.name}` + await warpgate.mutate(target.document, mutation, {}, mutateOptions) + } } export async function powers (options = {}) {