From d99d0c0728d96219c2a099ab34f27c4d0180ba75 Mon Sep 17 00:00:00 2001 From: Mike Bloy Date: Wed, 1 May 2024 21:14:27 -0500 Subject: [PATCH] base powers feature complete --- scripts/{allPowers.js => basePowers.js} | 179 ++++++++++++++++-------- scripts/powers.js | 33 ++++- 2 files changed, 149 insertions(+), 63 deletions(-) rename scripts/{allPowers.js => basePowers.js} (65%) diff --git a/scripts/allPowers.js b/scripts/basePowers.js similarity index 65% rename from scripts/allPowers.js rename to scripts/basePowers.js index 29cf1ee..1e547e3 100644 --- a/scripts/allPowers.js +++ b/scripts/basePowers.js @@ -2,7 +2,7 @@ import { moduleName } from './globals.js' const MAINTAIN_ICON = 'icons/magic/symbols/runes-star-blue.webp' -class PowerEffect { +export class PowerEffect { constructor (token, targets) { this.source = token this.targets = targets @@ -70,47 +70,44 @@ class PowerEffect { 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 modifiers () { - return [ - { 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 } ] - }, - { 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 } ] - }, - { name: 'Hinder', - id: 'hinder', - value: 1, - epic: false, - effect: true, + 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: '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 } ] + }) + if (this.isDamaging) { + 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 } ] - }, - { 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 } ] - }, - ] + }) + 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 } ] + }) + if (this.isDamaging) { + mods.push({ name: 'Lingering Damage', id: 'lingeringdamage', value: 2, + epic: false, effect: false}) + } + mods.push({ name: 'Selective', id: 'selective', value: 1, epic: false, effect: false }) + return mods } get menuData () { @@ -131,10 +128,7 @@ class PowerEffect { label += ` (${this.targets.length - 1} additional recipients ` + `+${this.additionalRecipientCost} ea.)` } - data.push({ - type: 'info', - label: label - }) + data.push({ type: 'info', label: label }) } for (const mod of this.modifiers) { data.push({ @@ -145,6 +139,23 @@ class PowerEffect { ), }) } + if (this.isDamaging) { + data.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}, + ] + }) + } + data.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 } @@ -195,6 +206,10 @@ class PowerEffect { this.data.mods.add(mod.id) } } + if (this.isDamaging) { + this.data.armorPiercing = this.data.values.shift() + } + this.data.range = this.data.values.shift() } async createSecondaryEffects (maintId) { @@ -206,7 +221,7 @@ 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.StartOfTurnAuto + doc.flags.swade.expiration = CONFIG.SWADE.CONST.STATUS_EFFECT_EXPIRATION.EndOfTurnAuto } else { doc.duration.seconds = 594 doc.flags[moduleName].maintId = maintId @@ -274,6 +289,21 @@ class PowerEffect { } async sideEffects () { + if (this.data.mods.has('fatigue')) { + for (const target of this.targets) { + const actor = target.actor + const update = { + system: { + fatigue: { + value: actor.system.fatigue.value + 1 + } + } + } + if (actor.system.fatigue.value < actor.system.fatigue.max) { + await actor.update(update) + } + } + } } get powerPoints () { @@ -286,37 +316,62 @@ class PowerEffect { if (this.targets.length > 1 && this.hasAdditionalRecipients) { total += (this.targets.length - 1) * this.additionalRecipientCost } + total += this.data.range + if (this.isDamaging) { + total += this.data.ap + } return total } - async chatMessage () { - let text = `Cast ${this.name}` + get chatMessageEffects () { + const list = [] + if (this.hasAdditionalRecipients && this.targets.length > 1) { + list.push(`${this.targets.length - 1} Additional Recipients`) + } + if (this.data.mods.has('adaptable')) { + list.push('Different Trapping (Adaptable Caster)') + } + if (this.data.mods.has('fatigue')) { + list.push('Fatigue (applied to targets') + } + if (this.data.mods.has('heavyweapon')) { + list.push('Heavy Weapon') + } + if (this.data.mods.has('lingeringdamage')) { + list.push('Lingering Damage') + } + if (this.data.mods.has('selective')) { + list.push('Selective') + } + if (this.isDamaging && this.data.armorPiercing > 0) { + list.push(`AP ${this.data.armorPiercing * 2}`) + } + if (this.data.range > 0) { + list.push(`Range ×${this.data.range +1}`) + } + return list + } + + get chatMessageText () { + let text = `

Cast ${this.name}` if (this.targets.length > 0) { text += ` on ${this.targets.map(t => t.name).join(', ')}` } + text += '

' + const effects = this.chatMessageEffects + if (effects.length > 0) { + text += '
Other Effects:
' + } + return text + } + + async chatMessage () { return ChatMessage.create({ flavor: `Calculated cost: ${this.powerPoints} pp`, speaker: ChatMessage.getSpeaker(this.source.actor), - content: text, + content: this.chatMessageText, whisper: ChatMessage.getWhisperRecipients('GM', game.user.name), }, { chatBubble: false }); } } - -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 effectName () { - return `${this.name} (${this.data.raise ? 'full' : 'half'} pace)` - } -} - -export const PowerClasses = { - burrow: BurrowEffect -} - diff --git a/scripts/powers.js b/scripts/powers.js index 4113b30..0ba1417 100644 --- a/scripts/powers.js +++ b/scripts/powers.js @@ -1,5 +1,36 @@ import { moduleName } from './globals.js' -import { PowerClasses } from './allPowers.js' +import { PowerEffect } from './basePowers.js' + +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 modifiers () { + const mods = super.modifiers + 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] ' : ''}` + + `(${this.data.raise ? 'full' : 'half'} pace)` + } +} + +const PowerClasses = { + burrow: BurrowEffect +} + +/* ---------------------------------------------------------------- */ export async function powerEffectManagementHook(effect, data, userId) { if (game.user.id !== userId) {