diff --git a/scripts/basePowers.js b/scripts/basePowers.js
index 1e547e3..35df242 100644
--- a/scripts/basePowers.js
+++ b/scripts/basePowers.js
@@ -118,7 +118,7 @@ export class PowerEffect {
}
get menuInputs () {
- const data = [
+ const inputs = [
{ type: 'header', label: `${this.name} Effect` },
{ type: 'info', label: `Apply ${this.name} Effect` },
]
@@ -128,10 +128,10 @@ export class PowerEffect {
label += ` (${this.targets.length - 1} additional recipients ` +
`+${this.additionalRecipientCost} ea.)`
}
- data.push({ type: 'info', label: label })
+ inputs.push({ type: 'info', label: label })
}
for (const mod of this.modifiers) {
- data.push({
+ inputs.push({
type: 'checkbox',
label: (
`${mod.epic ? '⭐ ' : ''}${mod.name} ` +
@@ -140,7 +140,7 @@ export class PowerEffect {
})
}
if (this.isDamaging) {
- data.push({ type: 'select', label: 'Armor Piercing',
+ inputs.push({ type: 'select', label: 'Armor Piercing',
options: [
{html: 'None', value: 0, selected: true},
{html: 'AP 2 (+1)', value: 1, selected: false},
@@ -149,14 +149,14 @@ export class PowerEffect {
]
})
}
- data.push({type: 'select', label: 'Range',
+ inputs.push({type: 'select', label: 'Range',
options: [
{html: 'Normal Range', value: 0, selected: true},
{html: 'Range ×2 (+1)', value: 1, selected: false},
{html: 'Range ×3 (+2)', value: 2, selected: false}
]
})
- return data
+ return inputs
}
get menuButtons () {
@@ -274,13 +274,15 @@ export class PowerEffect {
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 targetDocs = await this.secondaryDocsForTarget(secondaryDocs, target)
- if (this.duration > 0 || this.usePrimaryEffect) {
- targetDocs.push(await this.primaryDocForTarget(primaryDoc, target))
- }
- if (targetDocs.length > 0) {
- await this.applyActiveEffects(target, targetDocs)
+ if (this.isTargeted) {
+ for (const target of this.targets) {
+ const targetDocs = await this.secondaryDocsForTarget(secondaryDocs, target)
+ if (this.duration > 0 || this.usePrimaryEffect) {
+ targetDocs.push(await this.primaryDocForTarget(primaryDoc, target))
+ }
+ if (targetDocs.length > 0) {
+ await this.applyActiveEffects(target, targetDocs)
+ }
}
}
if (this.duration > 0) {
@@ -289,7 +291,7 @@ export class PowerEffect {
}
async sideEffects () {
- if (this.data.mods.has('fatigue')) {
+ if (this.data.mods.has('fatigue') && this.isTargeted) {
for (const target of this.targets) {
const actor = target.actor
const update = {
diff --git a/scripts/powers.js b/scripts/powers.js
index 59a1850..8d28267 100644
--- a/scripts/powers.js
+++ b/scripts/powers.js
@@ -27,6 +27,99 @@ class ArcaneProtectionEffect extends PowerEffect {
}
}
+class BanishEffect extends PowerEffect {
+ get name () { return 'Banish' }
+ get duration () { return 0 }
+ get basePowerPoints () { return 3 }
+ get usePrimaryEffect () { return false }
+ get isTargeted () { return true }
+ get menuInputs () {
+ const inputs = super.menuInputs
+ inputs.push
+ inputs.push({ type: 'select', label: '⭐ Area of Effect',
+ options: [
+ {html: 'None', value: 0, selected: true},
+ {html: 'Small Blast Template (+1)', value: 1, selected: false},
+ {html: 'Medium Blast Template (+2)', value: 1, selected: false},
+ {html: 'Large Blast Template (+3)', value: 1, selected: false},
+ ]})
+ return inputs
+ }
+ get powerPoints () {
+ let total = super.powerPoints
+ total += this.data.aoe
+ return total
+ }
+ get chatMessageEffects () {
+ const list = []
+ switch (this.data.aoe) {
+ case 0: break
+ case 1:
+ list.push('SBT')
+ break
+ case 2:
+ list.push('MBT')
+ break
+ case 3:
+ list.push('LBT')
+ break
+ }
+ list.push("Opposed Roll: caster's arcane skill vs target's Spirit.")
+ list.push("Success: Shaken, Each Raise: 1 Wound")
+ list.push("If target incapacitated by this, banishment to home plane")
+ return list
+ }
+
+ async parseValues () {
+ await super.parseValues()
+ this.data.aoe = this.data.values.shift()
+ }
+
+}
+
+class BarrierEffect extends PowerEffect {
+ get name () { return 'Barrier' }
+ get duration () { return 5 }
+ get icon () { return 'icons/environment/settlement/fence-stone-brick.webp' }
+ get isTargeted () { return false }
+ get basePowerPoints () { return 2 }
+ get usePrimaryEffect () { return false }
+ get modifiers () {
+ const mods = super.modifiers
+ mods.push({ name: 'Damage', id: 'damage', value: 1, epic: false, effect: false })
+ mods.push({ name: 'Damage (immaterial trapping)', id: 'damage', value: 0, epic: false, effect: false })
+
+ mods.push({ name: 'Deadly', id: 'deadly', value: 2, epic: true, effect: false })
+ mods.push({ name: 'Hardened', id: 'hardened', value: 1, epic: false, effect: false })
+ mods.push({ name: 'Shaped', id: 'shaped', value: 1, epic: false, effect: false })
+ mods.push({ name: 'Size', id: 'size', value: 1, epic: false, effect: false })
+ return mods
+ }
+ get chatMessageEffects () {
+ const list = []
+ const hardness = (this.data.raise ? 12 : 10) + (this.data.mods.has('hardened') ? 2 : 0)
+ list.push(`The Barrier is hardness ${hardness}`)
+ if (this.data.mods.has('damage')) {
+ list.push('Damage: 2d4 to anyone who contacts')
+ }
+ if (this.data.mods.has('deadly')) {
+ list.push('Deadly: 2d6 to anyone who contacts')
+ }
+ if (this.data.mods.has('shaped')) {
+ list.push('Shaped (circle, square, or rectangle)')
+ }
+ if (this.data.mods.has('size')) {
+ list.push('Size - length and height doubled')
+ }
+ return list
+ }
+ async createMaintainEffect (maintId) {
+ const doc = await super.createMaintainEffect(maintId)
+ doc.icon = this.icon
+ return doc
+ }
+}
+
class BurrowEffect extends PowerEffect {
get name () { return 'Burrow' }
get duration () { return 5 }
@@ -54,6 +147,8 @@ class BurrowEffect extends PowerEffect {
const PowerClasses = {
"arcane-protection": ArcaneProtectionEffect,
+ banish: BanishEffect,
+ barrier: BarrierEffect,
burrow: BurrowEffect
}