diff --git a/src/module/powers/detectConcealArcana.js b/src/module/powers/detectConcealArcana.js new file mode 100644 index 0000000..9d1b5f9 --- /dev/null +++ b/src/module/powers/detectConcealArcana.js @@ -0,0 +1,139 @@ +import { PowerEffect } from './basePowers.js'; + +export class DetectConcealArcanaEffect extends PowerEffect { + get name() { + return 'Detect/Conceal Arcana'; + } + + get icon() { + return this.data.detect + ? 'icons/magic/perception/third-eye-blue-red.webp' + : 'icons/magic/perception/silhouette-stealth-shadow.webp'; + } + + get duration() { + return this.data.detect ? 5 : 600; + } + + get basePowerPoints() { + return 2; + } + + get isTargeted() { + return true; + } + + get hasAdditionalRecipients() { + return true; + } + + get additionalRecipientCost() { + return (this.data?.aoe || 0) > 0 ? 0 : 1; + } + + get modifiers() { + const mods = super.modifiers; + mods.push({ + type: 'checkbox', + name: 'Alignment Sense (detect)', + value: 1, + id: 'alignment', + epic: false, + effect: false, + }); + mods.push({ + type: 'checkbox', + name: 'Identify (detect)', + value: 1, + id: 'identify', + epic: false, + effect: false, + }); + mods.push({ + type: 'checkbox', + name: 'Strong (conceal)', + value: 1, + id: 'strong', + epic: false, + effect: false, + }); + mods.push({ + sortOrder: -2, + name: 'Detect or Conceal?', + id: 'direction', + type: 'radio', + default: 'Detect', + epic: false, + choices: { Detect: 'Detect', Conceal: 'Conceal' }, + effects: { Detect: null, Conceal: null }, + values: { Detect: 0, Conceal: 0 }, + }); + mods.push({ + name: 'Area of Effect (conceal)', + type: 'select', + default: 'none', + epic: false, + choices: { none: 'None', mbt: 'Medium Blast Template', lbt: 'Large Blast Template' }, + effects: { none: null, mbt: null, lbt: null }, + values: { none: 0, mbt: 1, lbt: 2 }, + }); + return mods; + } + + get hasAoe() { + return true; + } + + async parseValues() { + await super.parseValues(); + this.data.detect = this.data.direction == 'Detect'; + } + + get powerPoints() { + return super.powerPoints + this.data.aoe; + } + + get effectName() { + return `${this.data.detect ? 'Detect' : 'Conceal'} Arcana`; + } + + get description() { + let desc = super.description; + if (this.data.detect) { + desc += `
The recipient can see and detect all supernatural persons, + objects, or effects in sight. This includes invisible foes, enchanted + objects, and so on.`; + if (this.data.raise) { + desc += `Since this was major Detect Arcana, the type of enchantments + is also known.`; + } + desc += `
If cast to learn more about a creature, the caster learns + active powers and arcane abilities.`; + if (this.data.raise) { + desc += `As major Detect in this mode, the caster also learns any + Weaknesses common to that creature type.`; + } + if (this.data.identify) { + desc += `
Items detected also give the recipient an idea of their + powers and how to activate them.
`; + } + if (this.data.alignment) { + desc += `The recipient can also detect the presence and location + of supernatural good or evil within range, regardless of line of sight.
`; + } + desc += `Invisible Creatures: The recipient may + also ignore ${this.data.raise ? 'all' : 'up to 4 points of'} penalties + when attacking invisible or magically concealed foes.
`; + } else { + let area = 'one item or being'; + if (this.data.aoe !== 0) { + area = `everything in a sphere the size of a + ${this.data.aoe === 1 ? 'Medium' : 'Large'} Blast Template`; + } + desc += `Conceal ${area} from the Detect Magic ability for + one hour. Attempts to detect arcana suffer a + ${(this.data.strong ? -2 : 0) + this.data.raise ? -2 : -4} penalty.`; + } + return desc; + } +} diff --git a/src/module/powers/powers.js b/src/module/powers/powers.js index 373e193..3d9a59d 100644 --- a/src/module/powers/powers.js +++ b/src/module/powers/powers.js @@ -16,148 +16,7 @@ import { CurseEffect } from './curse.js'; import { DamageFieldEffect } from './damageField.js'; import { DarksightEffect } from './darksight.js'; import { DeflectionEffect } from './deflection.js'; - -class DetectConcealArcanaEffect extends PowerEffect { - get name() { - return 'Detect/Conceal Arcana'; - } - - get icon() { - return this.data.detect - ? 'icons/magic/perception/third-eye-blue-red.webp' - : 'icons/magic/perception/silhouette-stealth-shadow.webp'; - } - - get duration() { - return this.data.detect ? 5 : 600; - } - - get basePowerPoints() { - return 2; - } - - get isTargeted() { - return true; - } - - get hasAdditionalRecipients() { - return true; - } - - get additionalRecipientCost() { - return (this.data?.aoe || 0) > 0 ? 0 : 1; - } - - get modifiers() { - const mods = super.modifiers; - mods.push({ - name: 'Alignment Sense (detect)', - value: 1, - id: 'alignment', - epic: false, - effect: false, - }); - mods.push({ - name: 'Identify (detect)', - value: 1, - id: 'identify', - epic: false, - effect: false, - }); - mods.push({ - name: 'Strong (conceal)', - value: 1, - id: 'strong', - epic: false, - effect: false, - }); - return mods; - } - - get hasAoe() { - return true; - } - - get menuInputs() { - const inputs = super.menuInputs; - inputs.push({ - type: 'select', - label: 'Area of Effect (conceal)', - options: [ - { html: 'None', value: 0, selected: true }, - { html: 'Medium Blast Template (+1)', value: 1, selected: false }, - { html: 'Large Blast Template (+2)', value: 2, selected: false }, - ], - }); - inputs.push({ type: 'info', label: 'Detect or Conceal?' }); - inputs.push({ - type: 'radio', - label: 'Detect', - options: ['isDetect', true], - }); - inputs.push({ - type: 'radio', - label: 'Conceal', - options: ['isDetect', false], - }); - return inputs; - } - - async parseValues() { - await super.parseValues(); - this.data.aoe = this.data.values.shift(); - this.data.values.shift(); - this.data.detect = this.data.values.shift(); - } - - get powerPoints() { - return super.powerPoints + this.data.aoe; - } - - get effectName() { - return `${this.data.detect ? 'Detect' : 'Conceal'} Arcana`; - } - - get description() { - let desc = super.description; - if (this.data.detect) { - desc += `
The recipient can see and detect all supernatural persons, - objects, or effects in sight. This includes invisible foes, enchanted - objects, and so on.`; - if (this.data.raise) { - desc += `Since this was major Detect Arcana, the type of enchantments - is also known.`; - } - desc += `
If cast to learn more about a creature, the caster learns - active powers and arcane abilities.`; - if (this.data.raise) { - desc += `As major Detect in this mode, the caster also learns any - Weaknesses common to that creature type.`; - } - if (this.data.mods.has('identify')) { - desc += `
Items detected also give the recipient an idea of their - powers and how to activate them.
`; - } - if (this.data.mods.has('alignment')) { - desc += `The recipient can also detect the presence and location - of supernatural good or evil within range, regardless of line of sight.
`; - } - desc += `Invisible Creatures: The recipient may - also ignore ${this.data.raise ? 'all' : 'up to 4 points of'} penalties - when attacking invisible or magically concealed foes.
`; - } else { - let area = 'one item or being'; - if (this.data.aoe !== 0) { - area = `everything in a sphere the size of a - ${this.data.aoe === 1 ? 'Medium' : 'Large'} Blast Template`; - } - desc += `Conceal ${area} from the Detect Magic ability for - one hour. Attempts to detect arcana suffer a - ${(this.data.mods.has('strong') ? -2 : 0) + this.data.raise ? -2 : -4} penalty.`; - } - return desc; - } -} +import { DetectConcealArcanaEffect } from './detectConcealArcana.js'; class DisguiseEffect extends PowerEffect { get name() { @@ -212,16 +71,20 @@ const PowerClasses = { blast: BlastEffect, blind: BlindEffect, bolt: BoltEffect, + 'boostlower-trait': BoostLowerTraitEffect, 'boost-lower-trait': BoostLowerTraitEffect, 'boost-trait': BoostLowerTraitEffect, burrow: BurrowEffect, burst: BurstEffect, + 'conceal-arcana': DetectConcealArcanaEffect, confusion: ConfusionEffect, curse: CurseEffect, 'damage-field': DamageFieldEffect, darksight: DarksightEffect, deflection: DeflectionEffect, + 'detect-arcana': DetectConcealArcanaEffect, 'detect-conceal-arcana': DetectConcealArcanaEffect, + 'detectconceal-arcana': DetectConcealArcanaEffect, disguise: DisguiseEffect, 'lower-trait': BoostLowerTraitEffect, };