diff --git a/eslint.config.mjs b/eslint.config.mjs index 898c452..7e6b14a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -12,17 +12,19 @@ export default [ languageOptions: { globals: { ...globals.browser, - ActiveEffect: true, - ChatMessage: true, - ColorAdjustmentsSamplerShader: true, - CONFIG: true, - foundry: true, - game: true, - Hooks: true, - socketlib: true, - ui: true, - VisionMode: true, - warpgate: true, + ActiveEffect: false, + ChatMessage: false, + ColorAdjustmentsSamplerShader: false, + CONFIG: false, + deepClone: false, + foundry: false, + game: false, + Hooks: false, + randomID: false, + socketlib: false, + ui: false, + VisionMode: false, + warpgate: false, } } }, diff --git a/scripts/allPowers.js b/scripts/allPowers.js new file mode 100644 index 0000000..3b9f4a4 --- /dev/null +++ b/scripts/allPowers.js @@ -0,0 +1,225 @@ +import { moduleName, log } from './globals.js' + +class PowerEffect { + constructor (token, targets) { + this.source = token + this.targets = targets + this.data = {} + } + + static async applyActiveEffects (token, effectDocuments) { + const mutation = { + embedded: { ActiveEffect: {} } + } + const mutateOptions = { + permanent: true, + description: effectDocuments[effectDocuments.length - 1]?.name + } + for (const effectDocument of effectDocuments) { + mutation.embedded.ActiveEffect[effectDocument.name] = effectDocument + } + await warpgate.mutate(token.document, mutation, {}, mutateOptions) + } + + static async getStatus (label, name, favorite = true) { + const effect = deepClone( + CONFIG.statusEffects.find(se => se.label === label)) + effect.name = ('name' in effect ? effect.name : effect.label) + if (!('flags' in effect)) { + effect.flags = {} + } + if (favorite) { + if (!('swade' in effect.flags)) { + effect.flags.swade = {} + } + effect.flags.swade.favorite = true + } + effect.flags.core = { statusId: effect.id } + return effect + } + + static createEffectDocument (icon, name, changes = null) { + if (changes === null) { + changes = [] + } + return { + icon, + name, + changes, + description: `
From ${this.source.name} casting ${this.name}
`, + flags: { + [moduleName]: { + powerEffect: true + }, swade: { + favorite: true, + expiration: CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnPrompt + } + } + } + } + + get name () { return 'Unknown Power' } + get icon () { return 'icons/magic/symbols/question-stone-yellow.webp' } + get duration () { return 5 } + get basePowerPoints () { return 0 } + get powerPoints () { return this.basePowerPoints } + get modifiers () { + return [ + { name: 'Glow', + id: 'glow', + value: 1, + advanced: false, + effect: true, + icon: 'icons/magic/light/orb-shadow-blue.webp', + changes: [ { key: '@Skill{Stealth}[system.die.modifier', value: -2, + priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ] + }, + { name: 'Shroud', + id: 'shroud', + value: 1, + advanced: false, + effect: true, + icon: 'icons/magic/perception/shadow-stealth-eyes-purple.webp', + changes: [ { key: '@Skill{Stealth}[system.die.modifier', value: 1, + priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ] + }, + { name: 'Hinder', + id: 'hinder', + value: 1, + advanced: false, + effect: true, + icon: 'icons/magic/control/debuff-chains-shackle-movement-red.webp', + changes: [ { key: 'system.stats.speed.value', value: -2, + priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ] + }, + { name: 'Hurry', + id: 'hurry', + value: 1, + advanced: false, + effect: true, + icon: 'icons/skills/movement/feet-winged-sandals-tan.webp', + changes: [ { key: 'system.stats.speed.value', value: 2, + priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ] + }, + ] + } + + get menuData () { + return { + inputs: this.menuInputs, + buttons: this.menuButtons, + } + } + + get menuInputs () { + const data = [ + { type: 'header', label: `${this.name} Effect` }, + { type: 'info', label: `Apply ${this.name} Effect` }, + ] + if (this.targets.length > 0) { + data.push({ + type: 'info', + label: `Targets: ${this.targets.map(t => t.name).join(',')}` + }) + } + for (const mod of this.modifiers) { + data.push({ + type: 'checkbox', + label: ( + `${mod.advanced ? '⭐ ' : ''}${mod.name} ` + + `(${mod.value >= 0 ? '+' : ''}${mod.value}` + ), + }) + } + return data + } + + get menuButtons () { + const data = [ + { label: 'Apply', value: 'apply' }, + { label: 'Apply with Raise', value: 'raise' }, + { label: 'Cancel', value: 'cancel' } + ] + return data + } + + get menuOptions () { + return { + title: `${this.name} Effect`, + defaultButton: 'Cancel', + options: {} + } + } + + async powerEffect () { + const { buttons, inputs } = await warpgate.menu( + this.menuData, this.menuOptions + ) + if (buttons && buttons !== 'cancel') { + this.data.button = buttons + this.data.values = inputs + await this.parseValues() + await this.apply() + await this.sideEffects() + } + } + + async parseValues () { + log(this.data.values) + log(this.data.choice) + this.data.rawValues = deepClone(this.data.values) + this.data.raise = this.data.button === 'raise' + for (let i = 0; i < 3; i++) { + this.data.values.shift() + } + this.data.mods = new Set() + for (const mod of this.modifiers) { + const modEnabled = this.data.values.shift() + if (modEnabled) { + this.data.mods.add(mod.id) + } + } + } + + modifierEffects (helperId) { + const docs = [] + for (const mod of this.modifiers) { + if (this.data.mods.has(mod.id) && mod.effect) { + const doc = this.createEffectDocument(mod.icon, mod.name, mod.changes) + doc.flags[moduleName].helperId = helperId + docs.push(doc) + } + } + return docs + } + + async apply () { + } + + async sideEffects () { + } +} + +class ActiveEffectPower extends PowerEffect { + async secondaryDocuments (helperId) { + const secondaryDocs = this.modiferEffects(helperId) + return secondaryDocs + } + + async apply () { + const helperId = randomID() + const secondaryDocs = this.secondaryDocuments(helperId) + const primaryDocument = this.primaryDocument(helperId) + } +} + +class BurrowEffect extends ActiveEffectPower { + get name () { return 'Burrow' } + get duration () { return 5 } + get icon () { return 'icons/magic/earth/projectile-stone-landslide.webp' } +} + +export const PowerClasses = { + burrow: BurrowEffect +} + diff --git a/scripts/module.js b/scripts/module.js index 5b9c0ed..b8a7420 100644 --- a/scripts/module.js +++ b/scripts/module.js @@ -3,6 +3,7 @@ import { requestTokenRoll } from './helpers.js' import { preDamageRollModifiers, preTraitRollModifiers } from './rollHelpers.js' import { shapeChangeOnDismiss } from './powerEffects.js' import { log, module } from './globals.js' +import { powerEffectManagementHook } from './powers.js' function _checkModule (name) { if (!game.modules.get(name)?.active && game.user.isGM) { @@ -91,6 +92,7 @@ Hooks.on('init', () => { Hooks.on('swadePreRollAttribute', preTraitRollModifiers) Hooks.on('swadePreRollSkill', preTraitRollModifiers) Hooks.on('swadeRollDamage', preDamageRollModifiers) +Hooks.on('deleteActiveEffect', powerEffectManagementHook) Hooks.on('ready', () => { _checkModule('warpgate') diff --git a/scripts/powers.js b/scripts/powers.js index 85172bd..516e82a 100644 --- a/scripts/powers.js +++ b/scripts/powers.js @@ -1,3 +1,12 @@ +import { PowerClasses } from './allPowers.js' + +export async function powerEffectManagementHook(effect, data, userId) { + console.log('Power Effect Management') + console.log(effect) + console.log(data) + console.log(userId) +} + export async function powers (options = {}) { const token = 'token' in options ? options.token : null if (token === undefined || token === null) { @@ -10,102 +19,10 @@ export async function powers (options = {}) { const swid = options?.name || item?.system.swid || null if (swid in PowerClasses) { - const runner = new PowerClasses[name](token, targets) + const runner = new PowerClasses[swid](token, targets) runner.powerEffect() return } ui.notifications.error(`No power effect found for ${name}`) } -const PowerClasses = { - 'burrow': BurrowEffect -} - -class PowerEffect { - constructor (token, targets) { - this.source = token - this.targets = targets - this.modifiers = [ - {name: 'Glow', id: 'glow', value: 1, advanced: false}, - {name: 'Shroud', id: 'shroud', value: 1, advanced: false}, - {name: 'Hinder', id: 'hinder', value: 1, advanced: false}, - {name: 'Hurry', id: 'hurry', value: 1, advanced: false}, - ] - } - - get name () { return 'Unknown Power' } - get icon () { return 'icons/magic/symbols/question-stone-yellow.webp' } - get duration () { return 5 } - - get menuData () { - return { - inputs: this.menuInputs, - buttons: this.menuButtons, - } - } - - get menuInputs () { - const data = [ - { type: 'header', label: `${this.name} Effect` }, - { type: 'info', label: `Apply ${this.name} Effect` }, - ] - if (this.targets.length > 0) { - data.push({ - type: 'info', - label: `Targets: ${this.targets.map(t => t.name).join(',')}` - }) - } - for (const mod of this.modifiers) { - data.push({ - type: 'checkbox', - label: ( - `${mod.advanced ? '⭐ ' : ''}${mod.name} ` + - `(${mod.value >= 0 ? '+' : ''}${mod.value}` - ), - }) - } - data.push({ type: 'header', label: '---------------' }) - return data - } - - get menuButtons () { - const data = [ - { label: 'Apply', value: 'apply' }, - { label: 'Apply with Raise', value: 'raise' }, - { label: 'Cancel', value: 'cancel' } - ] - return data - } - - get menuOptions () { - return { - title: `${this.name} Effect`, - defaultButton: 'Cancel', - options: {} - } - } - - async powerEffect () { - const { buttons, inputs } = await warpgate.menu( - this.menuData, this.menuOptions - ) - this.choice = buttons - this.values = inputs - if (this.choice && this.choice !== 'cancel') { - await this.parseValues() - await this.apply() - } - } - - async parseValues () { - } - - async applyResult () { - } -} - -class BurrowEffect extends PowerEffect { - get name () { return 'Burrow' } - get duration () { return 5 } - get icon () { return 'icons/magic/earth/projectile-stone-landslide.webp' } -}