diff --git a/CHANGELOG.md b/CHANGELOG.md index ebc089c..d1d3ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [3.0.0] UNRELEASED +### Added + +- Optional Visual Active Effect integration for power descriptions + ### Changed - Refactor and redo of powers handling diff --git a/src/module/globals.js b/src/module/globals.js index 434734c..283eb00 100644 --- a/src/module/globals.js +++ b/src/module/globals.js @@ -23,6 +23,10 @@ export class moduleHelpers { return 'system'; } + static get useVAE() { + return !!game.modules.get('visual-active-effects')?.active; + } + static getActorFolderByPath(path) { const names = path.split('/'); if (names[0] === '') { diff --git a/src/module/powers/banish.js b/src/module/powers/banish.js index 6962c51..35e9ed2 100644 --- a/src/module/powers/banish.js +++ b/src/module/powers/banish.js @@ -1,6 +1,5 @@ import { PowerEffect } from './basePowers.js'; import { requestRollFromTokens } from '../helpers.js'; -import { getPowerModifiers } from '../rollHelpers.js'; export class BanishEffect extends PowerEffect { get name() { diff --git a/src/module/powers/basePowers.js b/src/module/powers/basePowers.js index 0b53184..d892bfb 100644 --- a/src/module/powers/basePowers.js +++ b/src/module/powers/basePowers.js @@ -426,11 +426,40 @@ export class PowerEffect { return ''; } + get primaryEffectButtons() { + // button objects should have a label and a type. + // type should have one of the following, with the associated additional + // fields: + // roll: + // formula: dice formula eg '3d6 + 3' + // flavor: flavor text (optional) + // trait: + // rollType: 'attribute' or 'skill + // rollDesc: name or swid of the attribute or skill + // flavor: flavor text (optional) + // mods: list of mods { label, value, ignore } + // damage: + // formula: dice formula for example '1d4x[Blades]' + // ap: optional, a positive integer or 0, armor piercing + // flavor: flavor text (optional) + // callback: + // callback: the function callback to run, takes a token as an argument + return []; + } + async createPrimaryEffect(maintId) { const doc = this.createEffectDocument(this.icon, this.effectName, this.getPrimaryEffectChanges()); - doc.description += this.description; + if (moduleHelpers.useVAE) { + doc.flags['visual-active-effects'] = { data: { content: this.description } }; + } else { + doc.description += this.description; + } doc.flags[moduleName].maintId = maintId; doc.duration.seconds = 594; + const effectButtons = this.primaryEffectButtons; + if (effectButtons.length > 0) { + doc.flags[moduleName].buttons = effectButtons; + } return doc; } @@ -441,7 +470,11 @@ export class PowerEffect { } const doc = this.createEffectDocument(icon, `Maintaining ${this.effectName}`, []); doc.duration.rounds = this.duration; - doc.description += this.description; + if (moduleHelpers.useVAE) { + doc.flags['visual-active-effects'] = { data: { content: this.description } }; + } else { + doc.description += this.description; + } doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnPrompt; doc.flags.swade.loseTurnOnHold = true; doc.flags[moduleName].maintainingId = maintId; @@ -541,7 +574,7 @@ export class PowerEffect { if (this.isDamaging && this.data.ap > 0) { list.push(`AP ${this.data.ap}`); } - if (this.data.range != 'none') { + if (this.data.range ?? 'none' != 'none') { list.push(`Range ${this.data.range}`); } return list; diff --git a/src/module/powers/elementalManipulation.js b/src/module/powers/elementalManipulation.js new file mode 100644 index 0000000..86d6fac --- /dev/null +++ b/src/module/powers/elementalManipulation.js @@ -0,0 +1,97 @@ +import { PowerEffect } from './basePowers.js'; + +export class ElementalManipulationEffect extends PowerEffect { + get name() { + return 'Elemental Manipulation'; + } + + get icon() { + return 'icons/magic/earth/projectiles-stone-salvo-gray.webp'; + } + + get duration() { + return this.data?.weather ? 0 : 5; + } + + get isTargeted() { + return this.data?.weather ? false : true; + } + + get isRaisable() { + return true; + } + + get usePrimaryEffect() { + return this.data?.weather ? false : true; + } + + get oneTarget() { + return true; + } + + get basePowerPoints() { + return 5; + } + + get modifiers() { + return [ + { + name: 'Power', + type: 'checkbox', + value: 3, + id: 'power', + epic: true, + effect: false, + }, + { + name: 'Weather', + type: 'checkbox', + value: 5, + id: 'weather', + epic: true, + effect: false, + }, + ]; + } + + get primaryEffectButtons() { + const dmg = `${this.data.raise ? 3 : 2}d${this.data.power ? 6 : 4}`; + return [ + ...super.primaryEffectButtons, + { + type: 'damage', + label: `Damage (${dmg})`, + formula: `${dmg}x`, + }, + ]; + } + + get description() { + if (this.data.weather) { + return ( + super.description + + `Bring or disperse rain, snow, sun, and wind in about a five mile radius. + This takes 10 minutes and lasts an hour. + ` + ); + } + let damage = `${this.data.raise ? 3 : 2}d${this.data.power ? 6 : 4}x`; + return ( + super.description + + ` +
Use the activation roll for:
+