prettier and eslint formatting
This commit is contained in:
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { log, module } from './globals.js'
|
||||
import { log, moduleHelpers } from './globals.js'
|
||||
import { requestFearRollFromTokens, requestRollFromTokens } from './helpers.js'
|
||||
import { powerEffects } from './powerEffects.js'
|
||||
import { powers } from './powers.js'
|
||||
@@ -12,8 +12,8 @@ export class api {
|
||||
static globals () {
|
||||
const moduleName = 'swade-mb-helpers'
|
||||
game.modules.get(moduleName).api = {
|
||||
rulesVersion: module.rulesVersion,
|
||||
fearTable: module.fearTableHelper,
|
||||
rulesVersion: moduleHelpers.rulesVersion,
|
||||
fearTable: moduleHelpers.fearTableHelper,
|
||||
powerEffects,
|
||||
powers,
|
||||
requestRollFromTokens,
|
||||
|
||||
+222
-82
@@ -1,3 +1,4 @@
|
||||
/* globals warpgate */
|
||||
import { moduleName } from './globals.js'
|
||||
|
||||
const MAINTAIN_ICON = 'icons/magic/symbols/runes-star-blue.webp'
|
||||
@@ -11,8 +12,9 @@ export class PowerEffect {
|
||||
|
||||
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)
|
||||
CONFIG.statusEffects.find((se) => se.label === label)
|
||||
)
|
||||
effect.name = 'name' in effect ? effect.name : effect.label
|
||||
if (!('flags' in effect)) {
|
||||
effect.flags = {}
|
||||
}
|
||||
@@ -42,7 +44,8 @@ export class PowerEffect {
|
||||
},
|
||||
swade: {
|
||||
loseTurnOnHold: false,
|
||||
expiration: CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.StartOfTurnAuto
|
||||
expiration:
|
||||
CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.StartOfTurnAuto
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +58,6 @@ export class PowerEffect {
|
||||
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
|
||||
@@ -63,54 +65,164 @@ export class PowerEffect {
|
||||
await warpgate.mutate(token.document, mutation, {}, mutateOptions)
|
||||
}
|
||||
|
||||
get name () { return 'Unknown Power' }
|
||||
get effectName () { return this.name }
|
||||
get icon () { return 'icons/magic/symbols/question-stone-yellow.webp' }
|
||||
get duration () { return 5 }
|
||||
get basePowerPoints () { return 0 }
|
||||
get usePrimaryEffect () { return true }
|
||||
get hasAdditionalRecipients () { return false }
|
||||
get isDamaging () { return false }
|
||||
get additionalRecipientCost () { return 0 }
|
||||
get isTargeted () { return false }
|
||||
get oneTarget () { return false }
|
||||
get isRaisable () { return true }
|
||||
get hasAoe () { return false }
|
||||
get name () {
|
||||
return 'Unknown Power'
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
return this.name
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/symbols/question-stone-yellow.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isDamaging () {
|
||||
return false
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return false
|
||||
}
|
||||
|
||||
get oneTarget () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isRaisable () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
return false
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = []
|
||||
mods.push({ name: 'Adaptable Caster', id: 'adaptable',
|
||||
value: 1, epic: false, effect: false })
|
||||
mods.push({ name: 'Fatigue', id: 'fatigue', value: 2, epic: false, effect: false })
|
||||
mods.push({ name: 'Glow', id: 'glow', value: 1,
|
||||
epic: 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 } ]
|
||||
mods.push({
|
||||
name: 'Adaptable Caster',
|
||||
id: 'adaptable',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
mods.push({ name: 'Shroud', id: 'shroud', value: 1, epic: false, effect: true,
|
||||
mods.push({
|
||||
name: 'Fatigue',
|
||||
id: 'fatigue',
|
||||
value: 2,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
mods.push({
|
||||
name: 'Glow',
|
||||
id: 'glow',
|
||||
value: 1,
|
||||
epic: 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
|
||||
}
|
||||
]
|
||||
})
|
||||
mods.push({
|
||||
name: 'Shroud',
|
||||
id: 'shroud',
|
||||
value: 1,
|
||||
epic: 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 } ]
|
||||
changes: [
|
||||
{
|
||||
key: '@Skill{Stealth}[system.die.modifier]',
|
||||
value: 1,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
})
|
||||
if (this.isDamaging) {
|
||||
mods.push({ name: 'Heavy Weapon', id: 'heavyweapon', value: 2,
|
||||
epic: false, effect: false})
|
||||
mods.push({
|
||||
name: 'Heavy Weapon',
|
||||
id: 'heavyweapon',
|
||||
value: 2,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
}
|
||||
mods.push({ name: 'Hinder', id: 'hinder', value: 1, epic: 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 } ]
|
||||
mods.push({
|
||||
name: 'Hinder',
|
||||
id: 'hinder',
|
||||
value: 1,
|
||||
epic: 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
|
||||
}
|
||||
]
|
||||
})
|
||||
mods.push({ name: 'Hurry', id: 'hurry', value: 1, epic: false, effect: true,
|
||||
mods.push({
|
||||
name: 'Hurry',
|
||||
id: 'hurry',
|
||||
value: 1,
|
||||
epic: 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 } ]
|
||||
changes: [
|
||||
{
|
||||
key: 'system.stats.speed.value',
|
||||
value: 2,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
})
|
||||
if (this.isDamaging) {
|
||||
mods.push({ name: 'Lingering Damage', id: 'lingeringdamage', value: 2,
|
||||
epic: false, effect: false})
|
||||
mods.push({
|
||||
name: 'Lingering Damage',
|
||||
id: 'lingeringdamage',
|
||||
value: 2,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
}
|
||||
if (this.hasAoe) {
|
||||
mods.push({ name: 'Selective', id: 'selective', value: 1, epic: false, effect: false })
|
||||
mods.push({
|
||||
name: 'Selective',
|
||||
id: 'selective',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
}
|
||||
return mods
|
||||
}
|
||||
@@ -118,56 +230,61 @@ export class PowerEffect {
|
||||
get menuData () {
|
||||
return {
|
||||
inputs: this.menuInputs,
|
||||
buttons: this.menuButtons,
|
||||
buttons: this.menuButtons
|
||||
}
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = [
|
||||
{ type: 'header', label: `${this.name} Effect` },
|
||||
{ type: 'info', label: `Apply ${this.name} Effect (base cost ${this.basePowerPoints} pp)` },
|
||||
{
|
||||
type: 'info',
|
||||
label: `Apply ${this.name} Effect (base cost ${this.basePowerPoints} pp)`
|
||||
}
|
||||
]
|
||||
if (this.isTargeted) {
|
||||
let label = `<strong>Targets:</strong> ${this.targets.map(t => t.name).join(',')}`
|
||||
let label = `<strong>Targets:</strong> ${this.targets.map((t) => t.name).join(',')}`
|
||||
if (this.targets.length > 1 && this.hasAdditionalRecipients) {
|
||||
label += ` (${this.targets.length - 1} additional recipients ` +
|
||||
`+${this.additionalRecipientCost} ea.)`
|
||||
label +=
|
||||
` (${this.targets.length - 1} additional recipients ` +
|
||||
`+${this.additionalRecipientCost} ea.)`
|
||||
}
|
||||
inputs.push({ type: 'info', label: label })
|
||||
inputs.push({ type: 'info', label })
|
||||
}
|
||||
for (const mod of this.modifiers) {
|
||||
inputs.push({
|
||||
type: 'checkbox',
|
||||
label: (
|
||||
label:
|
||||
`${mod.epic ? '⭐ ' : ''}${mod.name} ` +
|
||||
`(${mod.value >= 0 ? '+' : ''}${mod.value})`
|
||||
),
|
||||
})
|
||||
}
|
||||
if (this.isDamaging) {
|
||||
inputs.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},
|
||||
{html: 'AP 4 (+2)', value: 2, selected: false},
|
||||
{html: 'AP 6 (+3)', value: 3, selected: false},
|
||||
{ html: 'None', value: 0, selected: true },
|
||||
{ html: 'AP 2 (+1)', value: 1, selected: false },
|
||||
{ html: 'AP 4 (+2)', value: 2, selected: false },
|
||||
{ html: 'AP 6 (+3)', value: 3, selected: false }
|
||||
]
|
||||
})
|
||||
}
|
||||
inputs.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}
|
||||
{ html: 'Normal Range', value: 0, selected: true },
|
||||
{ html: 'Range ×2 (+1)', value: 1, selected: false },
|
||||
{ html: 'Range ×3 (+2)', value: 2, selected: false }
|
||||
]
|
||||
})
|
||||
return inputs
|
||||
}
|
||||
|
||||
get menuButtons () {
|
||||
const data = [
|
||||
{ label: 'Apply', value: 'apply' },
|
||||
]
|
||||
const data = [{ label: 'Apply', value: 'apply' }]
|
||||
if (this.isRaisable) {
|
||||
data.push({ label: 'Apply with Raise', value: 'raise' })
|
||||
}
|
||||
@@ -186,7 +303,8 @@ export class PowerEffect {
|
||||
|
||||
async powerEffect () {
|
||||
const { buttons, inputs } = await warpgate.menu(
|
||||
this.menuData, this.menuOptions
|
||||
this.menuData,
|
||||
this.menuOptions
|
||||
)
|
||||
if (buttons && buttons !== 'cancel') {
|
||||
this.data.button = buttons
|
||||
@@ -229,7 +347,8 @@ export class PowerEffect {
|
||||
// set secondary effects of instant spells to expire on victim's next
|
||||
// turn
|
||||
doc.duration.rounds = 1
|
||||
doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnAuto
|
||||
doc.flags.swade.expiration =
|
||||
CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnAuto
|
||||
} else {
|
||||
doc.duration.seconds = 594
|
||||
doc.flags[moduleName].maintId = maintId
|
||||
@@ -242,18 +361,26 @@ export class PowerEffect {
|
||||
|
||||
getPrimaryEffectChanges () {
|
||||
const changes = [
|
||||
{ key: 'flags.swade-mb-helpers.powerAffected', value: 1,
|
||||
priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE } ]
|
||||
{
|
||||
key: 'flags.swade-mb-helpers.powerAffected',
|
||||
value: 1,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE
|
||||
}
|
||||
]
|
||||
return changes
|
||||
}
|
||||
|
||||
get description () {
|
||||
return ""
|
||||
return ''
|
||||
}
|
||||
|
||||
async createPrimaryEffect (maintId) {
|
||||
const doc = this.createEffectDocument(this.icon, this.effectName,
|
||||
this.getPrimaryEffectChanges())
|
||||
const doc = this.createEffectDocument(
|
||||
this.icon,
|
||||
this.effectName,
|
||||
this.getPrimaryEffectChanges()
|
||||
)
|
||||
doc.description += this.description
|
||||
doc.flags[moduleName].maintId = maintId
|
||||
doc.duration.seconds = 594
|
||||
@@ -265,23 +392,28 @@ export class PowerEffect {
|
||||
if (!this.usePrimaryEffect) {
|
||||
icon = this.icon
|
||||
}
|
||||
const doc = this.createEffectDocument(icon, `Maintaining ${this.effectName}`, [])
|
||||
const doc = this.createEffectDocument(
|
||||
icon,
|
||||
`Maintaining ${this.effectName}`,
|
||||
[]
|
||||
)
|
||||
doc.duration.rounds = this.duration
|
||||
doc.description += this.description
|
||||
doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnPrompt
|
||||
doc.flags.swade.expiration =
|
||||
CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnPrompt
|
||||
doc.flags.swade.loseTurnOnHold = true
|
||||
doc.flags[moduleName].maintainingId = maintId
|
||||
doc.flags[moduleName].targetIds = this.targets.map(t => t.id)
|
||||
doc.flags[moduleName].targetIds = this.targets.map((t) => t.id)
|
||||
return doc
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async secondaryDocsForTarget(docs, target) {
|
||||
async secondaryDocsForTarget (docs, target) {
|
||||
return deepClone(docs)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
async primaryDocForTarget(doc, target) {
|
||||
async primaryDocForTarget (doc, target) {
|
||||
const newDoc = deepClone(doc)
|
||||
newDoc.flags[moduleName].maintainingId = doc.flags[moduleName].maintId
|
||||
newDoc.flags[moduleName].targetIds = [target.id]
|
||||
@@ -295,7 +427,10 @@ export class PowerEffect {
|
||||
const maintainDoc = await this.createMaintainEffect(maintId)
|
||||
if (this.isTargeted) {
|
||||
for (const target of this.targets) {
|
||||
const targetDocs = await this.secondaryDocsForTarget(secondaryDocs, target)
|
||||
const targetDocs = await this.secondaryDocsForTarget(
|
||||
secondaryDocs,
|
||||
target
|
||||
)
|
||||
if (this.duration > 0 || this.usePrimaryEffect) {
|
||||
targetDocs.push(await this.primaryDocForTarget(primaryDoc, target))
|
||||
}
|
||||
@@ -368,7 +503,7 @@ export class PowerEffect {
|
||||
list.push(`AP ${this.data.armorPiercing * 2}`)
|
||||
}
|
||||
if (this.data.range > 0) {
|
||||
list.push(`Range ×${this.data.range +1}`)
|
||||
list.push(`Range ×${this.data.range + 1}`)
|
||||
}
|
||||
return list
|
||||
}
|
||||
@@ -376,7 +511,7 @@ export class PowerEffect {
|
||||
get chatMessageText () {
|
||||
let text = `<p>Cast ${this.name}`
|
||||
if (this.isTargeted && this.targets.length > 0) {
|
||||
text += ` on ${this.targets.map(t => t.name).join(', ')}`
|
||||
text += ` on ${this.targets.map((t) => t.name).join(', ')}`
|
||||
}
|
||||
text += '</p>'
|
||||
const desc = this.description
|
||||
@@ -385,18 +520,23 @@ export class PowerEffect {
|
||||
}
|
||||
const effects = this.chatMessageEffects
|
||||
if (effects.length > 0) {
|
||||
text += '<details><summary>Other Effects:</summary><ul><li>' +
|
||||
effects.join('</li><li>') + '</li></ul></details>'
|
||||
text +=
|
||||
'<details><summary>Other Effects:</summary><ul><li>' +
|
||||
effects.join('</li><li>') +
|
||||
'</li></ul></details>'
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
async chatMessage () {
|
||||
return ChatMessage.create({
|
||||
flavor: `Calculated cost: ${this.powerPoints} pp`,
|
||||
speaker: ChatMessage.getSpeaker(this.source.actor),
|
||||
content: this.chatMessageText,
|
||||
whisper: ChatMessage.getWhisperRecipients('GM', game.user.name),
|
||||
}, { chatBubble: false });
|
||||
return ChatMessage.create(
|
||||
{
|
||||
flavor: `Calculated cost: ${this.powerPoints} pp`,
|
||||
speaker: ChatMessage.getSpeaker(this.source.actor),
|
||||
content: this.chatMessageText,
|
||||
whisper: ChatMessage.getWhisperRecipients('GM', game.user.name)
|
||||
},
|
||||
{ chatBubble: false }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -1,14 +1,17 @@
|
||||
/* globals coreFearDialog */
|
||||
/* globals swpfFearDialog */
|
||||
/* globals warpgate */
|
||||
export const moduleName = 'swade-mb-helpers'
|
||||
|
||||
export function log (...args) {
|
||||
console.log('SWADE MB HELPERS |', ...args)
|
||||
}
|
||||
|
||||
export class module {
|
||||
export class moduleHelpers {
|
||||
static _socket = null
|
||||
|
||||
static get socket () {
|
||||
return module._socket
|
||||
return moduleHelpers._socket
|
||||
}
|
||||
|
||||
static get rulesVersion () {
|
||||
@@ -114,7 +117,7 @@ export class module {
|
||||
}
|
||||
|
||||
static get fearTableHelper () {
|
||||
switch (module.rulesVersion) {
|
||||
switch (moduleHelpers.rulesVersion) {
|
||||
case 'swade': return coreFearDialog // defined as global by the swade module
|
||||
case 'swpf': return swpfFearDialog // defined as global by the swpf module
|
||||
}
|
||||
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
import { module } from './globals.js'
|
||||
/* global warpgate */
|
||||
import { moduleHelpers } from './globals.js'
|
||||
|
||||
export async function requestFearRollFromTokens (tokens, options = {}) {
|
||||
// tokens: list of tokens to request the roll from
|
||||
@@ -59,7 +60,7 @@ export async function requestRollFromTokens (tokens, rollType, rollDesc, options
|
||||
if (additionalMods.length > 0) {
|
||||
rollOpts.additionalMods = additionalMods
|
||||
}
|
||||
promises.push(module.socket.executeAsUser(requestTokenRoll, owner.id,
|
||||
promises.push(moduleHelpers.socket.executeAsUser(requestTokenRoll, owner.id,
|
||||
token.scene.id, token.id, rollType, rollDesc, rollOpts))
|
||||
}
|
||||
const results = (await Promise.allSettled(promises)).map(r => r.value)
|
||||
|
||||
+8
-4
@@ -1,8 +1,12 @@
|
||||
/* globals ColorAdjustmentsSamplerShader */
|
||||
/* globals socketlib */
|
||||
/* globals VisionMode */
|
||||
/* globals warpgate */
|
||||
import { api } from './api.js'
|
||||
import { requestTokenRoll } from './helpers.js'
|
||||
import { preDamageRollModifiers, preTraitRollModifiers } from './rollHelpers.js'
|
||||
import { shapeChangeOnDismiss } from './powerEffects.js'
|
||||
import { log, module } from './globals.js'
|
||||
import { log, moduleHelpers } from './globals.js'
|
||||
import { powerEffectManagementHook } from './powers.js'
|
||||
|
||||
function _checkModule (name) {
|
||||
@@ -102,7 +106,7 @@ Hooks.on('ready', () => {
|
||||
})
|
||||
|
||||
Hooks.on('socketlib.ready', () => {
|
||||
const socket = socketlib.registerModule('swade-mb-helpers')
|
||||
socket.register('requestTokenRoll', requestTokenRoll)
|
||||
module._socket = socket
|
||||
const _socket = socketlib.registerModule('swade-mb-helpers')
|
||||
_socket.register('requestTokenRoll', requestTokenRoll)
|
||||
moduleHelpers._socket = _socket
|
||||
})
|
||||
|
||||
+36
-35
@@ -1,4 +1,5 @@
|
||||
import { log, module } from './globals.js'
|
||||
/* globals warpgate */
|
||||
import { log, moduleHelpers } from './globals.js'
|
||||
import { requestFearRollFromTokens, requestRollFromTokens } from './helpers.js'
|
||||
|
||||
class PowerEffect {
|
||||
@@ -70,12 +71,12 @@ class PowerEffect {
|
||||
|
||||
async applyResult () {
|
||||
for (const target of this.targets) {
|
||||
module.applyActiveEffects(target, this.effectDocs)
|
||||
moduleHelpers.applyActiveEffects(target, this.effectDocs)
|
||||
}
|
||||
}
|
||||
|
||||
static modEffectDoc (icon, name, key, value, durationRounds) {
|
||||
return module.createEffectDocument(icon, name, durationRounds, [
|
||||
return moduleHelpers.createEffectDocument(icon, name, durationRounds, [
|
||||
{
|
||||
key,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
@@ -160,7 +161,7 @@ class LingeringDamagePowerEffect extends TargetedPowerEffect {
|
||||
super.globalModifierEffects()
|
||||
this.inputIndex += 1
|
||||
if (this.inputs[7]) { // lingering damage
|
||||
const doc = module.createEffectDocument(
|
||||
const doc = moduleHelpers.createEffectDocument(
|
||||
'icons/magic/death/skull-poison-green.webp',
|
||||
`Lingering Damage (${this.name})`,
|
||||
1
|
||||
@@ -192,7 +193,7 @@ class ArcaneProtectionEffect extends TargetedPowerEffect {
|
||||
const icon = 'icons/magic/defensive/shield-barrier-flaming-pentagon-blue.webp'
|
||||
const name = `${greater ? 'Greater ' : ''}Arcane Protection (${raise ? 'major, ' : ''}${amount})`
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(icon, name, this.durationRounds, []))
|
||||
moduleHelpers.createEffectDocument(icon, name, this.durationRounds, []))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,12 +233,12 @@ class BlindEffect extends TargetedPowerEffect {
|
||||
}
|
||||
]
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
icon, `minor Blindness (Vigor ${strong ? '-2 ' : ''}ends)`,
|
||||
this.durationRounds, changes))
|
||||
if (raise) {
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
icon, `major Blindness (Vigor ${strong ? '-2 ' : ''}ends)`,
|
||||
this.durationRounds, changes)
|
||||
)
|
||||
@@ -253,7 +254,7 @@ class BurrowEffect extends TargetedPowerEffect {
|
||||
const raise = (this.buttons === 'raise')
|
||||
const icon = 'icons/magic/earth/projectile-stone-landslide.webp'
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
icon,
|
||||
`${raise ? 'major' : 'minor'} ${this.name}`,
|
||||
this.durationRounds,
|
||||
@@ -347,14 +348,14 @@ class BoostLowerTraitEffect extends TargetedPowerEffect {
|
||||
}
|
||||
const mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
const modValue = (direction === 'Boost' ? '+2' : '-2')
|
||||
const minorEffect = module.createEffectDocument(
|
||||
const minorEffect = moduleHelpers.createEffectDocument(
|
||||
icon, `minor ${namePart}`, durationRounds, [
|
||||
{ key: trait.diekey, mode, value: modValue, priority: 0 }
|
||||
])
|
||||
if (direction === 'Lower' && greater) {
|
||||
minorEffect.changes.push({ key: trait.modkey, mode, value: modValue, priority: 0 })
|
||||
}
|
||||
const majorEffect = module.createEffectDocument(
|
||||
const majorEffect = moduleHelpers.createEffectDocument(
|
||||
icon, `major ${namePart}`, durationRounds, [
|
||||
{ key: trait.diekey, mode, value: modValue, priority: 0 }
|
||||
])
|
||||
@@ -392,13 +393,13 @@ class ConfusionEffect extends TargetedPowerEffect {
|
||||
async prepResult () {
|
||||
const greater = !!this.inputs[this.inputIndex]
|
||||
if (this.buttons === 'distracted' || this.buttons === 'raise') {
|
||||
this.effectDocs.push(module.getStatus('SWADE.Distr', 'Distracted'))
|
||||
this.effectDocs.push(moduleHelpers.getStatus('SWADE.Distr', 'Distracted'))
|
||||
}
|
||||
if (this.buttons === 'vulnerable' || this.buttons === 'raise') {
|
||||
this.effectDocs.push(module.getStatus('SWADE.Vuln', 'Vulnerable'))
|
||||
this.effectDocs.push(moduleHelpers.getStatus('SWADE.Vuln', 'Vulnerable'))
|
||||
}
|
||||
if (greater) {
|
||||
this.effectDocs.push(module.getStatus('SWADE.Shaken', 'Shaken'))
|
||||
this.effectDocs.push(moduleHelpers.getStatus('SWADE.Shaken', 'Shaken'))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,7 +417,7 @@ class DarksightEffect extends TargetedPowerEffect {
|
||||
const greater = !!this.inputs[this.inputIndex]
|
||||
const icon = 'icons/magic/perception/eye-ringed-glow-angry-small-teal.webp'
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
icon,
|
||||
`${raise ? 'major' : 'minor'} ${this.name}${greater ? ' (greater)' : ''}`,
|
||||
this.durationRounds,
|
||||
@@ -433,7 +434,7 @@ class DisguiseEffect extends TargetedPowerEffect {
|
||||
const raise = this.buttons === 'raise'
|
||||
const icon = 'icons/skills/social/diplomacy-peace-alliance.webp'
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
icon,
|
||||
`${raise ? 'major' : 'minor'} ${this.name}`,
|
||||
this.durationRounds,
|
||||
@@ -463,7 +464,7 @@ class DeflectionEffect extends TargetedPowerEffect {
|
||||
async prepResult () {
|
||||
const effectName = `Deflection (${this.buttons === 'raise' ? 'all' : this.buttons})`
|
||||
const icon = 'icons/magic/defensive/shield-barrier-deflect-teal.webp'
|
||||
this.effectDocs.push(module.createEffectDocument(icon, effectName, this.durationRounds))
|
||||
this.effectDocs.push(moduleHelpers.createEffectDocument(icon, effectName, this.durationRounds))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,7 +495,7 @@ class DetectConcealArcanaEffect extends TargetedPowerEffect {
|
||||
? 'icons/magic/perception/third-eye-blue-red.webp'
|
||||
: 'icons/magic/perception/silhouette-stealth-shadow.webp')
|
||||
const name = `${raise ? 'major ' : ''}${isDetect ? 'Detect' : 'Conceal'} Arcana${strong ? ' (strong)' : ''}`
|
||||
const effect = module.createEffectDocument(icon, name, this.durationRounds, [])
|
||||
const effect = moduleHelpers.createEffectDocument(icon, name, this.durationRounds, [])
|
||||
this.effectDocs.push(effect)
|
||||
}
|
||||
}
|
||||
@@ -529,9 +530,9 @@ class EntangleEffect extends TargetedPowerEffect {
|
||||
const tough = !!this.inputs[this.inputIndex + 3]
|
||||
const effectSearch = (this.buttons === 'raise' ? 'SWADE.Bound' : 'SWADE.Entangled')
|
||||
const effectName = (this.buttons === 'raise' ? 'Bound' : 'Entangled')
|
||||
const effect = module.getStatus(effectSearch, effectName)
|
||||
const effect = moduleHelpers.getStatus(effectSearch, effectName)
|
||||
const extraIcon = 'icons/magic/nature/root-vine-barrier-wall-brown.webp'
|
||||
const extraEffect = module.createEffectDocument(extraIcon,
|
||||
const extraEffect = moduleHelpers.createEffectDocument(extraIcon,
|
||||
'Entangle Modifier', this.durationRounds, [])
|
||||
if (damage) {
|
||||
extraEffect.name = `${extraEffect.name} - ${damage} dmg`
|
||||
@@ -585,7 +586,7 @@ class HavocEffect extends TargetedPowerEffect {
|
||||
|
||||
async prepResult () {
|
||||
this.raise = (this.buttons === 'raise')
|
||||
this.effectDocs.unshift(module.getStatus('SWADE.Distr', 'Distracted'))
|
||||
this.effectDocs.unshift(moduleHelpers.getStatus('SWADE.Distr', 'Distracted'))
|
||||
}
|
||||
|
||||
async applyResult () {
|
||||
@@ -639,7 +640,7 @@ class IntangibilityEffect extends TargetedPowerEffect {
|
||||
|
||||
async prepResult () {
|
||||
const icon = 'icons/magic/control/debuff-energy-hold-levitate-blue-yellow.webp'
|
||||
const effect = module.createEffectDocument(icon, this.name, this.durationRounds, [])
|
||||
const effect = moduleHelpers.createEffectDocument(icon, this.name, this.durationRounds, [])
|
||||
this.effectDocs.push(effect)
|
||||
}
|
||||
}
|
||||
@@ -664,7 +665,7 @@ class InvisibilityEffect extends TargetedPowerEffect {
|
||||
}
|
||||
|
||||
async prepResult () {
|
||||
const effect = module.getStatus('EFFECT.StatusInvisible', 'Invisible')
|
||||
const effect = moduleHelpers.getStatus('EFFECT.StatusInvisible', 'Invisible')
|
||||
effect.duration = { rounds: this.durationRounds }
|
||||
this.effectDocs.push(effect)
|
||||
}
|
||||
@@ -688,7 +689,7 @@ class ProtectionEffect extends TargetedPowerEffect {
|
||||
}
|
||||
|
||||
async prepResult () {
|
||||
const effect = module.getStatus('SWADE.Protection', 'Protection')
|
||||
const effect = moduleHelpers.getStatus('SWADE.Protection', 'Protection')
|
||||
effect.duration = { rounds: this.durationRounds }
|
||||
const mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
effect.changes = [
|
||||
@@ -737,7 +738,7 @@ class ShapeChangeEffect extends TargetedPowerEffect {
|
||||
`${this.actorFolder}/${this.token.actor.name}`
|
||||
]
|
||||
for (const folderName of folderNames) {
|
||||
const folder = module.getActorFolderByPath(folderName)
|
||||
const folder = moduleHelpers.getActorFolderByPath(folderName)
|
||||
if (folder) {
|
||||
log(`Found actor folder ${folderName}`)
|
||||
folders.push(folder)
|
||||
@@ -753,7 +754,7 @@ class ShapeChangeEffect extends TargetedPowerEffect {
|
||||
const folders = await this.prepFolders()
|
||||
const actors = {}
|
||||
for (const folder of folders) {
|
||||
const folderActors = module.getActorsInFolder(folder)
|
||||
const folderActors = moduleHelpers.getActorsInFolder(folder)
|
||||
for (const key in folderActors) {
|
||||
actors[key] = folderActors[key]
|
||||
}
|
||||
@@ -826,7 +827,7 @@ class ShapeChangeEffect extends TargetedPowerEffect {
|
||||
}
|
||||
}
|
||||
this.effectDocs.push(
|
||||
module.createEffectDocument(
|
||||
moduleHelpers.createEffectDocument(
|
||||
this.icon,
|
||||
`Shape Change into ${this.protoDoc.name}`,
|
||||
this.durationRounds, effectChanges)
|
||||
@@ -931,7 +932,7 @@ class SmiteEffect extends TargetedPowerEffect {
|
||||
}
|
||||
|
||||
async prepResult () {
|
||||
this.baseEffect = module.getStatus('SWADE.Smite', 'Smite')
|
||||
this.baseEffect = moduleHelpers.getStatus('SWADE.Smite', 'Smite')
|
||||
}
|
||||
|
||||
async applyResult () {
|
||||
@@ -948,7 +949,7 @@ class SmiteEffect extends TargetedPowerEffect {
|
||||
]
|
||||
this.baseEffect.changes = changes
|
||||
this.baseEffect.name = effectName
|
||||
await module.applyActiveEffects(token, [this.baseEffect].concat(this.effectDocs))
|
||||
await moduleHelpers.applyActiveEffects(token, [this.baseEffect].concat(this.effectDocs))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -995,7 +996,7 @@ class SlothSpeedEffect extends TargetedPowerEffect {
|
||||
`${nameMods.length > 0 ? ' (' : ''}` +
|
||||
`${nameMods.join(', ')}${nameMods.length > 0 ? ')' : ''}`)
|
||||
const name = `${isSloth ? 'Sloth' : 'Speed'}${nameModifier}`
|
||||
const effect = module.createEffectDocument(
|
||||
const effect = moduleHelpers.createEffectDocument(
|
||||
icon, name, this.durationRounds, [
|
||||
{
|
||||
key: 'system.stats.speed.value',
|
||||
@@ -1038,7 +1039,7 @@ class SummonEffect extends PowerEffect {
|
||||
`${this.actorFolder}/${this.token.actor.name}`
|
||||
]
|
||||
for (const folderName of folderNames) {
|
||||
const folder = module.getActorFolderByPath(folderName)
|
||||
const folder = moduleHelpers.getActorFolderByPath(folderName)
|
||||
if (folder) {
|
||||
log(`Found actor folder ${folderName}`)
|
||||
folders.push(folder)
|
||||
@@ -1054,7 +1055,7 @@ class SummonEffect extends PowerEffect {
|
||||
const folders = await this.prepFolders()
|
||||
const actors = {}
|
||||
for (const folder of folders) {
|
||||
const folderActors = module.getActorsInFolder(folder)
|
||||
const folderActors = moduleHelpers.getActorsInFolder(folder)
|
||||
for (const key in folderActors) {
|
||||
actors[key] = folderActors[key]
|
||||
}
|
||||
@@ -1199,7 +1200,7 @@ class SummonEffect extends PowerEffect {
|
||||
modKeys.push(`@Skill{${skillList[i]}}[system.die.sides]`)
|
||||
}
|
||||
}
|
||||
const effectDoc = module.createEffectDocument(
|
||||
const effectDoc = moduleHelpers.createEffectDocument(
|
||||
this.ICON, 'Increased Trait', this.durationRounds)
|
||||
effectDoc.changes = modKeys.map(key => {
|
||||
return {
|
||||
@@ -1373,7 +1374,7 @@ class SummonAllyEffect extends SummonEffect {
|
||||
}
|
||||
}
|
||||
this.spawnMutation.embedded.ActiveEffect['Mirror Self'] =
|
||||
module.createEffectDocument(this.ICON, 'Mirror Self',
|
||||
moduleHelpers.createEffectDocument(this.ICON, 'Mirror Self',
|
||||
this.durationRounds, effectChanges)
|
||||
}
|
||||
}
|
||||
@@ -1586,7 +1587,7 @@ class ZombieEffect extends SummonEffect {
|
||||
}
|
||||
}
|
||||
if (this.armor) {
|
||||
const effectDoc = module.createEffectDocument(
|
||||
const effectDoc = moduleHelpers.createEffectDocument(
|
||||
'icons/equipment/chest/breastplate-layered-leather-stitched.webp',
|
||||
'Rotting Armor',
|
||||
0)
|
||||
@@ -1653,7 +1654,7 @@ class ZombieEffect extends SummonEffect {
|
||||
modKeys.push(`@Skill{${skillList[i]}}[system.die.sides]`)
|
||||
}
|
||||
}
|
||||
const effectDoc = module.createEffectDocument(
|
||||
const effectDoc = moduleHelpers.createEffectDocument(
|
||||
this.ICON, 'Increased Trait', this.durationRounds)
|
||||
effectDoc.changes = modKeys.map(key => {
|
||||
return {
|
||||
|
||||
+963
-295
@@ -1,13 +1,32 @@
|
||||
/* globals warpgate */
|
||||
import { moduleName } from './globals.js'
|
||||
import { PowerEffect } from './basePowers.js'
|
||||
|
||||
class ArcaneProtectionEffect extends PowerEffect {
|
||||
get name () { return 'Arcane Protection' }
|
||||
get duration () { return 5 }
|
||||
get icon () { return 'icons/magic/defensive/shield-barrier-flaming-pentagon-blue.webp' }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 1 }
|
||||
get isTargeted () { return true }
|
||||
get name () {
|
||||
return 'Arcane Protection'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/defensive/shield-barrier-flaming-pentagon-blue.webp'
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push({
|
||||
@@ -19,15 +38,20 @@ class ArcaneProtectionEffect extends PowerEffect {
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get _penaltyAmount () {
|
||||
return (this.data.raise ? -4 : -2) + (this.data.mods.has('greater') ? -2 : 0)
|
||||
return (
|
||||
(this.data.raise ? -4 : -2) + (this.data.mods.has('greater') ? -2 : 0)
|
||||
)
|
||||
}
|
||||
|
||||
get description () {
|
||||
let text = super.description
|
||||
text += `<p>Hostile powers are at ${this._penaltyAmount} when
|
||||
targeting or damaging the affected character.</p>`
|
||||
return text
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
const greater = this.data.mods.has('greater')
|
||||
const raise = this.data.raise
|
||||
@@ -37,41 +61,71 @@ 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 isRaisable () { return false }
|
||||
get hasAoe () { return true }
|
||||
get name () {
|
||||
return 'Banish'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 3
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get isRaisable () {
|
||||
return false
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
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: 2, selected: false},
|
||||
{html: 'Large Blast Template (+3)', value: 3, selected: false},
|
||||
]})
|
||||
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: 2, selected: false },
|
||||
{ html: 'Large Blast Template (+3)', value: 3, selected: false }
|
||||
]
|
||||
})
|
||||
return inputs
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
total += this.data.aoe
|
||||
return total
|
||||
}
|
||||
|
||||
get description () {
|
||||
return super.description + `
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>An opposed roll of the caster's skill vs the target's Spirit.
|
||||
<strong>Success:</strong> Shaken, <strong>each Raise:</strong> 1 Wound
|
||||
Incapacitation results in banishment to home plane.</p>
|
||||
`
|
||||
)
|
||||
}
|
||||
|
||||
get chatMessageEffects () {
|
||||
const list = super.chatMessageEffects
|
||||
switch (this.data.aoe) {
|
||||
case 0: break
|
||||
case 0:
|
||||
break
|
||||
case 1:
|
||||
list.push('SBT')
|
||||
break
|
||||
@@ -84,6 +138,7 @@ class BanishEffect extends PowerEffect {
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.aoe = this.data.values.shift()
|
||||
@@ -91,35 +146,102 @@ class BanishEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
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 isDamaging () { return true }
|
||||
get basePowerPoints () { return 2 }
|
||||
get usePrimaryEffect () { return false }
|
||||
get name () {
|
||||
return 'Barrier'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/environment/settlement/fence-stone-brick.webp'
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isDamaging () {
|
||||
return true
|
||||
}
|
||||
|
||||
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 })
|
||||
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 _length () {
|
||||
let height = 10
|
||||
if (this.data.raise) { height *= 2 }
|
||||
if (this.data.mods.has('size')) { height *= 2}
|
||||
return `${height}" (${height*2} yards)`
|
||||
if (this.data.raise) {
|
||||
height *= 2
|
||||
}
|
||||
if (this.data.mods.has('size')) {
|
||||
height *= 2
|
||||
}
|
||||
return `${height}" (${height * 2} yards)`
|
||||
}
|
||||
|
||||
get _height () {
|
||||
return `${this.data.mods.has('size') ? '2" (4' : '1" (2'} yards`
|
||||
}
|
||||
|
||||
get _hardness () {
|
||||
return (this.data.raise ? 12 : 10) + (this.data.mods.has('hardened') ? 2 : 0)
|
||||
return (
|
||||
(this.data.raise ? 12 : 10) + (this.data.mods.has('hardened') ? 2 : 0)
|
||||
)
|
||||
}
|
||||
|
||||
get description () {
|
||||
let text = super.description
|
||||
text += `<p>A barrier ${this._height} tall and ${this._length} long, of hardness ${this._hardness}. `
|
||||
@@ -137,35 +259,75 @@ class BarrierEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class BeastFriendEffect extends PowerEffect {
|
||||
get name () { return 'Beast Friend' }
|
||||
get duration () { return (this.data.mods.has('duration') ? 30 : 10) * 6 * 60 }
|
||||
get icon () { return 'icons/magic/nature/wolf-paw-glow-large-green.webp' }
|
||||
get isTargeted () { return true }
|
||||
get usePrimaryEffect () { return true }
|
||||
get name () {
|
||||
return 'Beast Friend'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return (this.data.mods.has('duration') ? 30 : 10) * 6 * 60
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/nature/wolf-paw-glow-large-green.webp'
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return true
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Bestiarium', value: 2, id: 'bestiarium', epic: true, effect: false },
|
||||
{ name: 'Duration', value: 1, id: 'duration', epic: false, effect: false },
|
||||
{ name: 'Mind Rider', value: 1, id: 'mindrider', epic: false, effect: false },
|
||||
{
|
||||
name: 'Bestiarium',
|
||||
value: 2,
|
||||
id: 'bestiarium',
|
||||
epic: true,
|
||||
effect: false
|
||||
},
|
||||
{
|
||||
name: 'Duration',
|
||||
value: 1,
|
||||
id: 'duration',
|
||||
epic: false,
|
||||
effect: false
|
||||
},
|
||||
{
|
||||
name: 'Mind Rider',
|
||||
value: 1,
|
||||
id: 'mindrider',
|
||||
epic: false,
|
||||
effect: false
|
||||
}
|
||||
)
|
||||
return mods
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
const pp = Math.max(
|
||||
this.targets.
|
||||
map(t => Math.max(t.actor.system.stats.size, 1)).
|
||||
reduce((a,b) => a+b, 0),
|
||||
1)
|
||||
inputs.push({ type: 'number', label: 'Base power points', options: pp})
|
||||
this.targets
|
||||
.map((t) => Math.max(t.actor.system.stats.size, 1))
|
||||
.reduce((a, b) => a + b, 0),
|
||||
1
|
||||
)
|
||||
inputs.push({ type: 'number', label: 'Base power points', options: pp })
|
||||
return inputs
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.basePP = this.data.values.shift()
|
||||
}
|
||||
get basePowerPoints () { return this?.data?.basePP || 2 }
|
||||
|
||||
get basePowerPoints () {
|
||||
return this?.data?.basePP || 2
|
||||
}
|
||||
|
||||
get description () {
|
||||
let text = super.description
|
||||
if (this.data.raise) {
|
||||
@@ -181,158 +343,289 @@ class BeastFriendEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class BlastEffect extends PowerEffect {
|
||||
get name () { return 'Blast' }
|
||||
get icon () { return 'icons/magic/fire/explosion-fireball-large-red-orange.webp' }
|
||||
get duration () { return 0 }
|
||||
get isTargeted () { return true }
|
||||
get usePrimaryEffect () { return false }
|
||||
get isDamaging () { return true }
|
||||
get basePowerPoints () { return 3 }
|
||||
get hasAoe () { return true }
|
||||
get name () {
|
||||
return 'Blast'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/fire/explosion-fireball-large-red-orange.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isDamaging () {
|
||||
return true
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 3
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
return true
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
inputs.push
|
||||
inputs.push({ type: 'select', label: 'Area of Effect',
|
||||
options: [
|
||||
{html: 'Small Blast Template (0)', value: 's', selected: false},
|
||||
{html: 'Medium Blast Template (0)', value: 'm', selected: true},
|
||||
{html: 'Large Blast Template (+1)', value: 'l', selected: false},
|
||||
]})
|
||||
inputs.push({
|
||||
type: 'select',
|
||||
label: 'Area of Effect',
|
||||
options: [
|
||||
{ html: 'Small Blast Template (0)', value: 's', selected: false },
|
||||
{ html: 'Medium Blast Template (0)', value: 'm', selected: true },
|
||||
{ html: 'Large Blast Template (+1)', value: 'l', selected: false }
|
||||
]
|
||||
})
|
||||
return inputs
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Damage', value: 2, id: 'damage', epic: false, effect: false },
|
||||
{ name: 'Greater Blast', value: 4, id: 'greater', epic: true, effect: false },
|
||||
{
|
||||
name: 'Greater Blast',
|
||||
value: 4,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
}
|
||||
)
|
||||
return mods
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
total += (this.data.aoe === 'l' ? 1 : 0)
|
||||
total += this.data.aoe === 'l' ? 1 : 0
|
||||
return total
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.aoe = this.data.values.shift()
|
||||
}
|
||||
|
||||
get description () {
|
||||
const dmgDie = (
|
||||
this.data.mods.has('greater') ? 4 :
|
||||
(this.data.mods.has('damage') ? 3 : 2)) + (this.data.raise ? 1 : 0)
|
||||
const size = (
|
||||
this.data.aoe === 'l' ? 'LBT' : (this.data.aoe === 's' ? 'SBT' : 'MBT'))
|
||||
return super.description + `
|
||||
const dmgDie =
|
||||
(this.data.mods.has('greater')
|
||||
? 4
|
||||
: this.data.mods.has('damage')
|
||||
? 3
|
||||
: 2) + (this.data.raise ? 1 : 0)
|
||||
const size =
|
||||
this.data.aoe === 'l' ? 'LBT' : this.data.aoe === 's' ? 'SBT' : 'MBT'
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>The blast covers a ${size} and does ${dmgDie}d6 damage</p>`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class BlindEffect extends PowerEffect {
|
||||
get name () { return 'Blind' }
|
||||
get icon () { return 'icons/skills/wounds/injury-eyes-blood-red.webp' }
|
||||
get duration () { return 0 }
|
||||
get isTargeted () { return true }
|
||||
get hasAoe () { return true }
|
||||
get basePowerPoints () { return 2 }
|
||||
get name () {
|
||||
return 'Blind'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/skills/wounds/injury-eyes-blood-red.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
return true
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 2
|
||||
}
|
||||
|
||||
getPrimaryEffectChanges () {
|
||||
const changes = [
|
||||
{ key: 'system.stats.globalMods.trait', value: -2,
|
||||
priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ]
|
||||
{
|
||||
key: 'system.stats.globalMods.trait',
|
||||
value: -2,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
return changes
|
||||
}
|
||||
|
||||
get description () {
|
||||
return super.description +
|
||||
return (
|
||||
super.description +
|
||||
`<p>${this.data.raise ? -4 : -2} penalty to all actions involving sight.</p>
|
||||
<p>Shake off attempts at end of turns with a Vigor
|
||||
${this.data.mods.has('strong') ? '-2 ' : ''}roll as a free action.
|
||||
Success removes 2 points of penalties. A raise removes the effect.</p>`
|
||||
)
|
||||
}
|
||||
|
||||
async createSecondaryEffects (maintId) {
|
||||
const docs = await super.createSecondaryEffects(maintId)
|
||||
if (this.data.raise) {
|
||||
const strong = this.data.mods.has('strong')
|
||||
const doc = this.createEffectDocument(
|
||||
this.icon, `Blinded (${strong ? 'Strong, ' : ''}Raise)`, [
|
||||
{ key: 'system.stats.globalMods.trait', value: -2,
|
||||
priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD }
|
||||
])
|
||||
this.icon,
|
||||
`Blinded (${strong ? 'Strong, ' : ''}Raise)`,
|
||||
[
|
||||
{
|
||||
key: 'system.stats.globalMods.trait',
|
||||
value: -2,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
)
|
||||
doc.duration.seconds = 594
|
||||
doc.description = this.description +
|
||||
"<p>This is the raise effect which can be shaken off separately.</p>"
|
||||
doc.description =
|
||||
this.description +
|
||||
'<p>This is the raise effect which can be shaken off separately.</p>'
|
||||
doc.flags[moduleName].maintId = maintId
|
||||
docs.push(doc)
|
||||
}
|
||||
return docs
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Strong', value: 1, id: 'strong', epic: false, effect: false },
|
||||
)
|
||||
mods.push({
|
||||
name: 'Strong',
|
||||
value: 1,
|
||||
id: 'strong',
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
inputs.push
|
||||
inputs.push({ type: 'select', label: 'Area of Effect',
|
||||
options: [
|
||||
{html: 'None', value: 0, selected: true},
|
||||
{html: 'Medium Blast Template (+2)', value: 2, selected: false},
|
||||
{html: 'Large Blast Template (+3)', value: 3, selected: false},
|
||||
]})
|
||||
inputs.push({
|
||||
type: 'select',
|
||||
label: 'Area of Effect',
|
||||
options: [
|
||||
{ html: 'None', value: 0, selected: true },
|
||||
{ html: 'Medium Blast Template (+2)', value: 2, selected: false },
|
||||
{ html: 'Large Blast Template (+3)', value: 3, selected: false }
|
||||
]
|
||||
})
|
||||
return inputs
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.aoe = this.data.values.shift()
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
total += this.data.aoe
|
||||
return total
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
const strong = this.data.mods.has('strong')
|
||||
return `Blinded${strong ? ' (Strong)' : ''}`
|
||||
}
|
||||
|
||||
get chatMessageEffects () {
|
||||
const list = super.chatMessageEffects
|
||||
switch (this.data.aoe) {
|
||||
case 2: list.push('MBT'); break
|
||||
case 3: list.push('LBT'); break
|
||||
case 2:
|
||||
list.push('MBT')
|
||||
break
|
||||
case 3:
|
||||
list.push('LBT')
|
||||
break
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
class BoltEffect extends PowerEffect {
|
||||
get name () { return 'Bolt' }
|
||||
get icon () { return 'icons/magic/fire/explosion-fireball-large-red-orange.webp' }
|
||||
get duration () { return 0 }
|
||||
get isTargeted () { return true }
|
||||
get isDamaging () { return true }
|
||||
get basePowerPoints () { return 3 }
|
||||
get usePrimaryEffect () { return false }
|
||||
get name () {
|
||||
return 'Bolt'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/fire/explosion-fireball-large-red-orange.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get isDamaging () {
|
||||
return true
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 3
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return false
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Damage', value: 2, id: 'damage', epic: false, effect: false },
|
||||
{ name: 'Disintegrate', value: 1, id: 'disintigrate', epic: true, effect: false },
|
||||
{ name: 'Greater Bolt', value: 4, id: 'greater', epic: true, effect: false },
|
||||
{ name: 'Rate of Fire', value: 2, id: 'rof', epic: true, effect: false },
|
||||
{
|
||||
name: 'Disintegrate',
|
||||
value: 1,
|
||||
id: 'disintigrate',
|
||||
epic: true,
|
||||
effect: false
|
||||
},
|
||||
{
|
||||
name: 'Greater Bolt',
|
||||
value: 4,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
},
|
||||
{ name: 'Rate of Fire', value: 2, id: 'rof', epic: true, effect: false }
|
||||
)
|
||||
return mods
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
total += (this.data.aoe === 'l' ? 1 : 0)
|
||||
total += this.data.aoe === 'l' ? 1 : 0
|
||||
return total
|
||||
}
|
||||
|
||||
get description () {
|
||||
const dmgDie = (
|
||||
this.data.mods.has('greater') ? 4 :
|
||||
(this.data.mods.has('damage') ? 3 : 2)) + (this.data.raise ? 1 : 0)
|
||||
const dmgDie =
|
||||
(this.data.mods.has('greater')
|
||||
? 4
|
||||
: this.data.mods.has('damage')
|
||||
? 3
|
||||
: 2) + (this.data.raise ? 1 : 0)
|
||||
let desc = super.description + '<p>'
|
||||
if (this.data.mods.has('rof')) {
|
||||
desc += `Up to two bolts (RoF 2) do ${dmgDie}d6 damage each.`
|
||||
@@ -340,7 +633,8 @@ class BoltEffect extends PowerEffect {
|
||||
desc += `The bolt does ${dmgDie}d6 damage.`
|
||||
}
|
||||
if (this.data.mods.has('disintegrate')) {
|
||||
desc += 'The bolt is <em>disintegrating</em>. If being used to break' +
|
||||
desc +=
|
||||
'The bolt is <em>disintegrating</em>. If being used to break' +
|
||||
' something, the damage dice can Ace. A creature Incapacitated by a ' +
|
||||
'disintegrating bolt must make a Vigor roll or its body turns to dust'
|
||||
}
|
||||
@@ -350,53 +644,95 @@ class BoltEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class BurrowEffect extends PowerEffect {
|
||||
get name () { return 'Burrow' }
|
||||
get duration () { return 5 }
|
||||
get icon () { return 'icons/magic/earth/projectile-stone-landslide.webp' }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 1 }
|
||||
get basePowerPoints () { return 1 }
|
||||
get isTargeted () { return true }
|
||||
get name () {
|
||||
return 'Burrow'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/earth/projectile-stone-landslide.webp'
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Power',
|
||||
id: 'power',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false,
|
||||
})
|
||||
mods.push({
|
||||
name: 'Power',
|
||||
id: 'power',
|
||||
value: 1,
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
return `${this.name} ${this.data.mods.has('power') ? '[Power] ' : ''}` +
|
||||
return (
|
||||
`${this.name} ${this.data.mods.has('power') ? '[Power] ' : ''}` +
|
||||
`(${this.data.raise ? 'full' : 'half'} pace)`
|
||||
)
|
||||
}
|
||||
get description() {
|
||||
let text = super.description +
|
||||
|
||||
get description () {
|
||||
let text =
|
||||
super.description +
|
||||
`<p>Meld into the ground. Move at ${this.data.raise ? 'full' : 'half'} pace. May not run.</p>`
|
||||
if (this.data.mods.has('power')) {
|
||||
text += `<p>Can <em>burrow</em> through solid stone, concrete, etc</p>`
|
||||
text += '<p>Can <em>burrow</em> through solid stone, concrete, etc</p>'
|
||||
}
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
class BoostLowerTraitEffect extends PowerEffect {
|
||||
get name () { return 'Boost/Lower Trait' }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 2 }
|
||||
get name () {
|
||||
return 'Boost/Lower Trait'
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 2
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return (this?.data?.direction === 'Boost' ?
|
||||
'icons/magic/life/cross-embers-glow-yellow-purple.webp' :
|
||||
'icons/magic/movement/chevrons-down-yellow.webp'
|
||||
)
|
||||
return this?.data?.direction === 'Boost'
|
||||
? 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
|
||||
: 'icons/magic/movement/chevrons-down-yellow.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return (this?.data?.direction === 'Boost' ? 5 : 0)
|
||||
return this?.data?.direction === 'Boost' ? 5 : 0
|
||||
}
|
||||
get isTargeted () { return true }
|
||||
get basePowerPoints () { return 3 }
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 3
|
||||
}
|
||||
|
||||
getPrimaryEffectChanges () {
|
||||
let modValue = '2'
|
||||
if (this.data.raise && this.data.direction === 'Boost') {
|
||||
@@ -404,32 +740,48 @@ class BoostLowerTraitEffect extends PowerEffect {
|
||||
}
|
||||
modValue = (this.data.direction === 'Boost' ? '+' : '-') + modValue
|
||||
const changes = [
|
||||
{ key: this.data.trait.diekey, value: modValue,
|
||||
priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ]
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
if (this.data.direction === 'Lower' && this.data.mods.has('greater')) {
|
||||
changes.push({
|
||||
key: this.data.trait.modkey, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
value: -2, priority: 0})
|
||||
key: this.data.trait.modkey,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,
|
||||
value: -2,
|
||||
priority: 0
|
||||
})
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
async createSecondaryEffects (maintId) {
|
||||
const docs = await super.createSecondaryEffects(maintId)
|
||||
if (this.data.raise && this.data.direction === 'Lower') {
|
||||
const name = 'major ' + this.effectName
|
||||
const modValue = (this.data.direction === 'Boost' ? '+2': '-2')
|
||||
const modValue = this.data.direction === 'Boost' ? '+2' : '-2'
|
||||
const changes = [
|
||||
{ key: this.data.trait.diekey, value: modValue,
|
||||
priority: 0, mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD } ]
|
||||
{
|
||||
key: this.data.trait.diekey,
|
||||
value: modValue,
|
||||
priority: 0,
|
||||
mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD
|
||||
}
|
||||
]
|
||||
const doc = this.createEffectDocument(this.icon, name, changes)
|
||||
doc.duration.seconds = 594
|
||||
doc.description = this.description +
|
||||
"<p>This is the raise effect which can be shaken off separately.</p>"
|
||||
doc.description =
|
||||
this.description +
|
||||
'<p>This is the raise effect which can be shaken off separately.</p>'
|
||||
doc.flags[moduleName].maintId = maintId
|
||||
docs.push(doc)
|
||||
}
|
||||
return docs
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
let name = `${this.data.direction} ${this.data.trait.name}`
|
||||
const nameMods = []
|
||||
@@ -444,9 +796,10 @@ class BoostLowerTraitEffect extends PowerEffect {
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
get description () {
|
||||
let desc = super.description
|
||||
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' :''}`
|
||||
const amount = `${this.data.raise ? 2 : 1} die type${this.data.raise ? 's' : ''}`
|
||||
desc += `<p>${this.data.direction === 'Boost' ? 'Raise' : 'Lower'} the
|
||||
target's ${this.data.trait.name} die type ${amount}.`
|
||||
if (this.data.mods.has('greater')) {
|
||||
@@ -467,15 +820,26 @@ class BoostLowerTraitEffect extends PowerEffect {
|
||||
}
|
||||
return desc
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{name: 'Greater Boost/Lower Trailt', value: 2, id: 'greater', epic: true, effect: false})
|
||||
mods.push(
|
||||
{ name: 'Strong (lower only)', value: 1, id: 'strong', epic: false, effect: false }
|
||||
)
|
||||
mods.push({
|
||||
name: 'Greater Boost/Lower Trailt',
|
||||
value: 2,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
})
|
||||
mods.push({
|
||||
name: 'Strong (lower only)',
|
||||
value: 1,
|
||||
id: 'strong',
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
let traitOptions = ['Agility', 'Smarts', 'Spirit', 'Strength', 'Vigor']
|
||||
@@ -491,14 +855,14 @@ class BoostLowerTraitEffect extends PowerEffect {
|
||||
}
|
||||
}
|
||||
for (const token of this.targets) {
|
||||
const skills = token.actor.items.filter(item => item.type === 'skill')
|
||||
const skills = token.actor.items.filter((item) => item.type === 'skill')
|
||||
for (const skill of skills) {
|
||||
const name = skill.name
|
||||
traits[name] = {
|
||||
name,
|
||||
type: 'skill',
|
||||
modkey: `@Skill{${name}}[system.die.modifier]`,
|
||||
diekey: `@Skill{${name}}[system.die.sides]`,
|
||||
diekey: `@Skill{${name}}[system.die.sides]`
|
||||
}
|
||||
if (name !== 'Unskilled') {
|
||||
allSkills.add(name)
|
||||
@@ -507,99 +871,172 @@ class BoostLowerTraitEffect extends PowerEffect {
|
||||
}
|
||||
traitOptions = traitOptions.concat(Array.from(allSkills).sort())
|
||||
this.data.traits = traits
|
||||
inputs.push({type: 'select', label: 'Trait', options: traitOptions})
|
||||
inputs.push({type: 'info', label: 'Boost or Lower?'})
|
||||
inputs.push({type: 'radio', label: 'Boost', options: ['isBoost', true]})
|
||||
inputs.push({type: 'radio', label: 'Lower', options: ['isBoost', false]})
|
||||
inputs.push({ type: 'select', label: 'Trait', options: traitOptions })
|
||||
inputs.push({ type: 'info', label: 'Boost or Lower?' })
|
||||
inputs.push({ type: 'radio', label: 'Boost', options: ['isBoost', true] })
|
||||
inputs.push({ type: 'radio', label: 'Lower', options: ['isBoost', false] })
|
||||
return inputs
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.trait = this.data.traits[this.data.values.shift()]
|
||||
this.data.values.shift()
|
||||
this.data.direction = this.data.values.shift() ? 'Boost' : 'Lower'
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
const total = super.powerPoints
|
||||
return total
|
||||
}
|
||||
}
|
||||
|
||||
class BurstEffect extends PowerEffect {
|
||||
get name () { return 'Blast' }
|
||||
get icon () { return 'icons/magic/sonic/projectile-shock-wave-blue.webp' }
|
||||
get duration () { return 0 }
|
||||
get isTargeted () { return true }
|
||||
get usePrimaryEffect () { return false }
|
||||
get isDamaging () { return true }
|
||||
get basePowerPoints () { return 3 }
|
||||
get hasAoe () { return true }
|
||||
get name () {
|
||||
return 'Blast'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/sonic/projectile-shock-wave-blue.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return false
|
||||
}
|
||||
|
||||
get isDamaging () {
|
||||
return true
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 3
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
return true
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Damage', value: 2, id: 'damage', epic: false, effect: false },
|
||||
{ name: 'Greater Burst', value: 4, id: 'greater', epic: true, effect: false },
|
||||
{
|
||||
name: 'Greater Burst',
|
||||
value: 4,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
}
|
||||
)
|
||||
return mods
|
||||
}
|
||||
|
||||
get description () {
|
||||
const dmgDie = (
|
||||
this.data.mods.has('greater') ? 4 :
|
||||
(this.data.mods.has('damage') ? 3 : 2)) + (this.data.raise ? 1 : 0)
|
||||
return super.description + `
|
||||
const dmgDie =
|
||||
(this.data.mods.has('greater')
|
||||
? 4
|
||||
: this.data.mods.has('damage')
|
||||
? 3
|
||||
: 2) + (this.data.raise ? 1 : 0)
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>The blast covers a Cone or Stream template and does ${dmgDie}d6 damage</p>`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ConfusionEffect extends PowerEffect {
|
||||
get name () { return 'Confusion' }
|
||||
get icon () { return 'icons/magic/control/hypnosis-mesmerism-swirl.webp' }
|
||||
get duration () { return 0 }
|
||||
get isTargeted () { return true }
|
||||
get usePrimaryEffect () { return false }
|
||||
get basePowerPoints () { return 2 }
|
||||
get hasAoe () { return true }
|
||||
get name () {
|
||||
return 'Confusion'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/control/hypnosis-mesmerism-swirl.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 0
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get usePrimaryEffect () {
|
||||
return false
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 2
|
||||
}
|
||||
|
||||
get hasAoe () {
|
||||
return true
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
inputs.push
|
||||
inputs.push({ type: 'select', label: 'Area of Effect',
|
||||
options: [
|
||||
{html: 'Small Blast Template (0)', value: 's', selected: false},
|
||||
{html: 'Medium Blast Template (0)', value: 'm', selected: true},
|
||||
{html: 'Large Blast Template (+1)', value: 'l', selected: false},
|
||||
]})
|
||||
inputs.push({
|
||||
type: 'select',
|
||||
label: 'Area of Effect',
|
||||
options: [
|
||||
{ html: 'Small Blast Template (0)', value: 's', selected: false },
|
||||
{ html: 'Medium Blast Template (0)', value: 'm', selected: true },
|
||||
{ html: 'Large Blast Template (+1)', value: 'l', selected: false }
|
||||
]
|
||||
})
|
||||
return inputs
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push(
|
||||
{ name: 'Greater Confusion', value: 2, id: 'greater', epic: true, effect: false },
|
||||
)
|
||||
mods.push({
|
||||
name: 'Greater Confusion',
|
||||
value: 2,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get powerPoints () {
|
||||
let total = super.powerPoints
|
||||
total += (this.data.aoe === 'l' ? 1 : 0)
|
||||
total += this.data.aoe === 'l' ? 1 : 0
|
||||
return total
|
||||
}
|
||||
|
||||
get menuButtons () {
|
||||
const data = [
|
||||
{ label: 'Apply with Distracted', value: 'distracted' },
|
||||
{ label: 'Apply with Vulnerable', value: 'vulnerable' },
|
||||
{ label: 'Apply with both (raise)', value: 'raise' },
|
||||
{ label: 'Cancel', value: 'cancel' },
|
||||
{ label: 'Cancel', value: 'cancel' }
|
||||
]
|
||||
return data
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.distracted = this.data.button === 'distracted' || this.data.button === 'raise'
|
||||
this.data.vulnerable = this.data.button === 'vulnerable' || this.data.button === 'raise'
|
||||
this.data.distracted =
|
||||
this.data.button === 'distracted' || this.data.button === 'raise'
|
||||
this.data.vulnerable =
|
||||
this.data.button === 'vulnerable' || this.data.button === 'raise'
|
||||
this.data.aoe = this.data.values.shift()
|
||||
}
|
||||
|
||||
get description () {
|
||||
const size = (
|
||||
this.data.aoe === 'l' ? 'LBT' : (this.data.aoe === 's' ? 'SBT' : 'MBT'))
|
||||
const size =
|
||||
this.data.aoe === 'l' ? 'LBT' : this.data.aoe === 's' ? 'SBT' : 'MBT'
|
||||
let effect = 'Vulnerable'
|
||||
if (this.data.raise) {
|
||||
effect = 'both Distracted and Vulnerable'
|
||||
@@ -609,39 +1046,75 @@ class ConfusionEffect extends PowerEffect {
|
||||
if (this.data.mods.has('Greater')) {
|
||||
effect += ' as well as Shaken'
|
||||
}
|
||||
return super.description + `
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>The targets in the ${size} are ${effect}.</p>`
|
||||
)
|
||||
}
|
||||
|
||||
async createSecondaryEffects (maintId) {
|
||||
const docs = await super.createSecondaryEffects(maintId)
|
||||
if (this.data.distracted) {
|
||||
PowerEffect.getStatus('SWADE.Distr', 'Distracted', false).then(v => docs.push(v))
|
||||
PowerEffect.getStatus('SWADE.Distr', 'Distracted', false).then((v) =>
|
||||
docs.push(v)
|
||||
)
|
||||
}
|
||||
if (this.data.distracted) {
|
||||
PowerEffect.getStatus('SWADE.Vuln', 'Vulnerable', false).then(v => docs.push(v))
|
||||
PowerEffect.getStatus('SWADE.Vuln', 'Vulnerable', false).then((v) =>
|
||||
docs.push(v)
|
||||
)
|
||||
}
|
||||
if (this.data.mods.has('greater')) {
|
||||
PowerEffect.getStatus('SWADE.Shaken', 'Shaken', false).then(v => docs.push(v))
|
||||
PowerEffect.getStatus('SWADE.Shaken', 'Shaken', false).then((v) =>
|
||||
docs.push(v)
|
||||
)
|
||||
}
|
||||
return docs
|
||||
}
|
||||
}
|
||||
|
||||
class CurseEffect extends PowerEffect {
|
||||
get name () { return 'Curse' }
|
||||
get icon () { return 'icons/magic/control/voodoo-doll-pain-damage-purple.webp' }
|
||||
get duration () { return 500*24*60*6 }
|
||||
get isTargeted () { return true }
|
||||
get oneTarget () { return true }
|
||||
get isRaisable () { return false }
|
||||
get basePowerPoints () { return 5 }
|
||||
get name () {
|
||||
return 'Curse'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/control/voodoo-doll-pain-damage-purple.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 500 * 24 * 60 * 6
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get oneTarget () {
|
||||
return true
|
||||
}
|
||||
|
||||
get isRaisable () {
|
||||
return false
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push({
|
||||
name: 'Turn to Stone', value: 5, id: 'turntostone', epic: true, effect: false
|
||||
name: 'Turn to Stone',
|
||||
value: 5,
|
||||
id: 'turntostone',
|
||||
epic: true,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get description () {
|
||||
let desc = super.description
|
||||
desc += `<p>The victim must defend with a Spirit roll opposed by the
|
||||
@@ -664,21 +1137,67 @@ class CurseEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class DamageFieldEffect extends PowerEffect {
|
||||
get name () { return 'Damage Field' }
|
||||
get icon () { return 'icons/magic/defensive/shield-barrier-blades-teal.webp' }
|
||||
get duration () { return 5 }
|
||||
get basePowerPoints () { return 4 }
|
||||
get isTargeted () { return true }
|
||||
get oneTarget () { return true }
|
||||
get isRaisable () { return false }
|
||||
get name () {
|
||||
return 'Damage Field'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/defensive/shield-barrier-blades-teal.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 4
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get oneTarget () {
|
||||
return true
|
||||
}
|
||||
|
||||
get isRaisable () {
|
||||
return false
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push({ name: 'Area of Effect', value: 2, id: 'aoe', epic: false, effect: false })
|
||||
mods.push({ name: 'Damage', value: 2, id: 'damage', epic: false, effect: false })
|
||||
mods.push({ name: 'Greater Damage Field', value: 4, id: 'greater', epic: true, effect: false })
|
||||
mods.push({ name: 'Mobile', value: 2, id: 'mobile', epic: false, effect: false })
|
||||
mods.push({
|
||||
name: 'Area of Effect',
|
||||
value: 2,
|
||||
id: 'aoe',
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
mods.push({
|
||||
name: 'Damage',
|
||||
value: 2,
|
||||
id: 'damage',
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
mods.push({
|
||||
name: 'Greater Damage Field',
|
||||
value: 4,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
})
|
||||
mods.push({
|
||||
name: 'Mobile',
|
||||
value: 2,
|
||||
id: 'mobile',
|
||||
epic: false,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get description () {
|
||||
let desc = super.description
|
||||
let area = 'all adjacent creatures'
|
||||
@@ -700,6 +1219,7 @@ class DamageFieldEffect extends PowerEffect {
|
||||
desc += '</p>'
|
||||
return desc
|
||||
}
|
||||
|
||||
getPrimaryEffectChanges () {
|
||||
const base = 'flags.swade.auras.damagefield'
|
||||
const priority = 0
|
||||
@@ -709,26 +1229,59 @@ class DamageFieldEffect extends PowerEffect {
|
||||
{ key: `${base}.walls`, value: true, priority, mode },
|
||||
{ key: `${base}.color`, value: '#ffcc00', priority, mode },
|
||||
{ key: `${base}.alpha`, value: 0.1, priority, mode },
|
||||
{ key: `${base}.radius`, value: (this.data.mods.has('aoe') ? 1.5 : 0.5), priority, mode },
|
||||
{ key: `${base}.visibleTo`, value: [-1, 0, 1], priority, mode },
|
||||
{
|
||||
key: `${base}.radius`,
|
||||
value: this.data.mods.has('aoe') ? 1.5 : 0.5,
|
||||
priority,
|
||||
mode
|
||||
},
|
||||
{ key: `${base}.visibleTo`, value: [-1, 0, 1], priority, mode }
|
||||
]
|
||||
return changes
|
||||
}
|
||||
}
|
||||
|
||||
class DarksightEffect extends PowerEffect {
|
||||
get name () { return 'Darksight' }
|
||||
get icon () { return 'icons/magic/perception/eye-ringed-glow-angry-small-teal.webp' }
|
||||
get duration () { return 600 }
|
||||
get basePowerPoints () { return 1 }
|
||||
get isTargeted () { return true }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 1 }
|
||||
get name () {
|
||||
return 'Darksight'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/perception/eye-ringed-glow-angry-small-teal.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 600
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
const mods = super.modifiers
|
||||
mods.push({name: 'Greater Darksight', value: 2, id: 'greater', epic: true, effect: false})
|
||||
mods.push({
|
||||
name: 'Greater Darksight',
|
||||
value: 2,
|
||||
id: 'greater',
|
||||
epic: true,
|
||||
effect: false
|
||||
})
|
||||
return mods
|
||||
}
|
||||
|
||||
get description () {
|
||||
let desc = super.description
|
||||
desc += '<p>'
|
||||
@@ -736,13 +1289,16 @@ class DarksightEffect extends PowerEffect {
|
||||
desc += `Can see in all darkness, ignoring all illumination penalties and
|
||||
4 points of penalties from invisible creatures`
|
||||
} else if (this.data.raise) {
|
||||
desc += 'Can see in Pitch Darkness and ignore up to 6 points of illumination penalties'
|
||||
desc +=
|
||||
'Can see in Pitch Darkness and ignore up to 6 points of illumination penalties'
|
||||
} else {
|
||||
desc += 'Can see in darkness and ignore 4 points of illumination penalties'
|
||||
desc +=
|
||||
'Can see in darkness and ignore 4 points of illumination penalties'
|
||||
}
|
||||
desc += '</p>'
|
||||
return desc
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
if (this.data.mods.has('greater')) {
|
||||
return 'Greater Darksight'
|
||||
@@ -755,78 +1311,163 @@ class DarksightEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class DeflectionEffect extends PowerEffect {
|
||||
get name () { return 'Deflection' }
|
||||
get icon () { return 'icons/magic/defensive/shield-barrier-deflect-teal.webp' }
|
||||
get duration () { return 5 }
|
||||
get basePowerPoints () { return 2 }
|
||||
get isTargeted () { return true }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 1 }
|
||||
get name () {
|
||||
return 'Deflection'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/magic/defensive/shield-barrier-deflect-teal.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 5
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 2
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get menuButtons () {
|
||||
const data = [
|
||||
{ label: 'Melee', value: 'melee' },
|
||||
{ label: 'Ranged', value: 'vulnerable' },
|
||||
{ label: 'Raise (both)', value: 'raise' },
|
||||
{ label: 'Cancel', value: 'cancel' },
|
||||
{ label: 'Cancel', value: 'cancel' }
|
||||
]
|
||||
return data
|
||||
}
|
||||
|
||||
async parseValues () {
|
||||
await super.parseValues()
|
||||
this.data.affects = this.data.button === 'raise' ? 'all' : this.data.button
|
||||
}
|
||||
|
||||
get effectName () {
|
||||
return `Deflection (${this.data.affects})`
|
||||
}
|
||||
|
||||
get description () {
|
||||
return super.description + `<p>Attackers subtract -2 from ${this.data.affects}
|
||||
return (
|
||||
super.description +
|
||||
`<p>Attackers subtract -2 from ${this.data.affects}
|
||||
attacks when targeting this creature.</p>`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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 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})
|
||||
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 hasAoe () {
|
||||
return true
|
||||
}
|
||||
|
||||
get menuInputs () {
|
||||
const inputs = super.menuInputs
|
||||
inputs.push({ type: 'select', label: 'Area of Effect (conceal)',
|
||||
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]})
|
||||
{ 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) {
|
||||
@@ -837,7 +1478,7 @@ class DetectConcealArcanaEffect extends PowerEffect {
|
||||
desc += `Since this was major Detect Arcana, the type of enchantments
|
||||
is also known.`
|
||||
}
|
||||
desc+= `</p><p>If cast to learn more about a creature, the caster learns
|
||||
desc += `</p><p>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
|
||||
@@ -869,53 +1510,80 @@ class DetectConcealArcanaEffect extends PowerEffect {
|
||||
}
|
||||
|
||||
class DisguiseEffect extends PowerEffect {
|
||||
get name () { return 'Disguise' }
|
||||
get icon () { return 'icons/equipment/head/mask-carved-wood-white.webp' }
|
||||
get duration () { return 100 }
|
||||
get basePowerPoints () { return 2 }
|
||||
get isTargeted () { return true }
|
||||
get hasAdditionalRecipients () { return true }
|
||||
get additionalRecipientCost () { return 1 }
|
||||
get name () {
|
||||
return 'Disguise'
|
||||
}
|
||||
|
||||
get icon () {
|
||||
return 'icons/equipment/head/mask-carved-wood-white.webp'
|
||||
}
|
||||
|
||||
get duration () {
|
||||
return 100
|
||||
}
|
||||
|
||||
get basePowerPoints () {
|
||||
return 2
|
||||
}
|
||||
|
||||
get isTargeted () {
|
||||
return true
|
||||
}
|
||||
|
||||
get hasAdditionalRecipients () {
|
||||
return true
|
||||
}
|
||||
|
||||
get additionalRecipientCost () {
|
||||
return 1
|
||||
}
|
||||
|
||||
get modifiers () {
|
||||
return [
|
||||
...super.modifiers,
|
||||
{name: 'Size', value: 1, id: 'size', epic: false, effect: false}
|
||||
{ name: 'Size', value: 1, id: 'size', epic: false, effect: false }
|
||||
]
|
||||
}
|
||||
|
||||
get description () {
|
||||
let size = this.data.mods.has('size') ? 'of the same size as' : 'within two sizes of'
|
||||
return super.description + `
|
||||
const size = this.data.mods.has('size')
|
||||
? 'of the same size as'
|
||||
: 'within two sizes of'
|
||||
return (
|
||||
super.description +
|
||||
`
|
||||
<p>Assume the appearance of another person ${size} the recipient. Anyone
|
||||
who has cause to doubt the disguise may make a Notice roll at ${this.data.raise ? -4 : -4}
|
||||
as a free action to see through the disguise.</p>`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const PowerClasses = {
|
||||
"arcane-protection": ArcaneProtectionEffect,
|
||||
'arcane-protection': ArcaneProtectionEffect,
|
||||
banish: BanishEffect,
|
||||
barrier: BarrierEffect,
|
||||
"beast-friend": BeastFriendEffect,
|
||||
'beast-friend': BeastFriendEffect,
|
||||
blast: BlastEffect,
|
||||
blind: BlindEffect,
|
||||
bolt: BoltEffect,
|
||||
"boost-lower-trait": BoostLowerTraitEffect,
|
||||
"boost-trait": BoostLowerTraitEffect,
|
||||
'boost-lower-trait': BoostLowerTraitEffect,
|
||||
'boost-trait': BoostLowerTraitEffect,
|
||||
burrow: BurrowEffect,
|
||||
burst: BurstEffect,
|
||||
confusion: ConfusionEffect,
|
||||
curse: CurseEffect,
|
||||
"damage-field": DamageFieldEffect,
|
||||
'damage-field': DamageFieldEffect,
|
||||
darksight: DarksightEffect,
|
||||
deflection: DeflectionEffect,
|
||||
"detect-conceal-arcana": DetectConcealArcanaEffect,
|
||||
"disguise" : DisguiseEffect,
|
||||
"lower-trait": BoostLowerTraitEffect,
|
||||
'detect-conceal-arcana': DetectConcealArcanaEffect,
|
||||
disguise: DisguiseEffect,
|
||||
'lower-trait': BoostLowerTraitEffect
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
export async function powerEffectManagementHook(effect, data, userId) {
|
||||
export async function powerEffectManagementHook (effect, data, userId) {
|
||||
if (game.user.id !== userId) {
|
||||
return
|
||||
}
|
||||
@@ -939,9 +1607,10 @@ export async function powerEffectManagementHook(effect, data, userId) {
|
||||
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
|
||||
(e) => e.getFlag(moduleName, 'maintId') === maintId
|
||||
)
|
||||
for (const efct of effects) {
|
||||
mutation.embedded.ActiveEffect[efct.id] = warpgate.CONST.DELETE
|
||||
}
|
||||
mutateOptions.description = `${effect.parent.name} is no longer ${effect.name} on ${target.name}`
|
||||
await warpgate.mutate(target.document, mutation, {}, mutateOptions)
|
||||
@@ -966,4 +1635,3 @@ export async function powers (options = {}) {
|
||||
}
|
||||
ui.notifications.error(`No power effect found for ${name}`)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,8 @@
|
||||
import { log, module } from './globals.js'
|
||||
import { log } from './globals.js'
|
||||
|
||||
export async function preTraitRollModifiers (actor, trait, roll, modifiers, options) {
|
||||
const targets = Array.from(game.user.targets)
|
||||
const token = game.canvas.tokens.controlled.length > 0 ? game.canvas.tokens.controlled[0] : null
|
||||
// log('ACTOR', actor)
|
||||
// log('TOKEN', token)
|
||||
// log('TRAIT', trait)
|
||||
// log('ROLL', roll)
|
||||
// log('MODIFIERS', modifiers)
|
||||
// log('OPTIONS', options)
|
||||
// log('TARGET', targets)
|
||||
if (targets.some(target => target.actor.system.status.isVulnerable)) {
|
||||
modifiers.push({ label: 'Target is Vulnerable', value: '+2', ignore: false })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user