import { moduleHelpers, moduleName } from '../globals.js'; import { firstOwner, updateOwnedToken } from '../helpers.js'; import { ActorFolderEffect } from './basePowers.js'; export class BalefulPolymorphEffect extends ActorFolderEffect { get name() { return 'Baleful Polymorph'; } get icon() { return 'icons/magic/control/silhouette-hold-change-blue.webp'; } get duration() { return this.data.duration ? 50 : 5; } get isTargeted() { return true; } get oneTarget() { return true; } get isRaisable() { return true; } get basePowerPoints() { return 3; } get hasRange() { return false; } actorValue(actor) { const size = actor.system.stats.size; const targetSize = this.targets[0].actor.system.stats.size; return Math.abs(targetSize - size); } get modifiers() { return [ ...super.modifiers, { name: 'Duration', type: 'checkbox', value: 2, id: 'duration', epic: true, effect: false, }, { name: 'Victim critical failure', type: 'checkbox', default: false, id: 'critfail', epic: false, value: 0, effect: false, }, ]; } async parseValues() { await super.parseValues(); this.target = this?.targets?.[0]; this.data.actorUpdates = { name: `${this.target.actor.name} (${this.targetActor.name} form)`, system: { wildcard: this.target.actor.system.wildcard, attributes: {}, }, }; const attrList = ['spirit']; if (!this.data.critfail) { attrList.push('smarts'); } for (const stat of attrList) { this.data.actorUpdates.system.attributes[stat] = { die: this.target.actor.system.attributes[stat].die, 'wild-die': this.target.actor.system.attributes[stat]['wild-die'], }; } this.data.tokenUpdates = { flags: { [moduleName]: { 'shapeChange.srcTokenUuid': this.target.document.uuid, 'shapeChange.srcTokenId': this.target.document.id, 'shapeChange.srcTokenSceneId': this.target.scene.id, }, }, actorLink: false, name: `${this.target.name} (${this.targetActor.prototypeToken.name} form)`, disposition: this.target.document.disposition, sight: { enabled: true, }, }; this.data.embeddedUpdates = { ActiveEffect: {}, Item: {}, }; for (const effect of this.target.actor.effects) { const doc = foundry.utils.deepClone(await this.target.actor.getEmbeddedDocument('ActiveEffect', effect.id)); this.data.embeddedUpdates.ActiveEffect[effect.name] = doc; } } async spawn() { const target = this.target.document; const size = target.parent.dimensions.size; const protoWidth = this.targetActor.prototypeToken.width; const protoHeight = this.targetActor.prototypeToken.height; this.targetTokenDoc.updateSource({ x: target.x - ((protoWidth - target.width) * size) / 2, y: target.y - ((protoHeight - target.height) * size) / 2, elevation: target.elevation, hidden: target.hidden, }); return this.source.scene.createEmbeddedDocuments('Token', [this.targetTokenDoc]); } async apply() { await super.apply(); const maintainDoc = await this.createMaintainEffect(this.data.maintId); maintainDoc.flags[moduleName].targetIds = this.data.spawned.map((t) => t.id); maintainDoc.flags[moduleName].shapeChangeSourceId = this.target.id; maintainDoc.flags[moduleName].shapeChangeTempTokenId = this.data.spawned[0].id; let maintainer = this.source; if (this.source.id === this.target.id) { maintainer = this.data.spawned[0]; } await this.applyActiveEffects(maintainer, [maintainDoc]); } get effectName() { return `Baleful Polymorph into ${this.targetActor.prototypeToken.name}`; } get spawnUpdates() { const updates = super.spawnUpdates; foundry.utils.mergeObject(updates.actor, this.data.actorUpdates); foundry.utils.mergeObject(updates.token, this.data.tokenUpdates); foundry.utils.mergeObject(updates.embedded, this.data.embeddedUpdates); return updates; } async sideEffects() { const owner = firstOwner(this.target); moduleHelpers.socket.executeAsUser( updateOwnedToken, owner.id, this.target.document.parent.id, this.target.document.id, { hidden: true, x: 0, y: 0 }, { animate: false }, ); } get description() { let desc = super.description; desc += `
On losing an opposed roll vs the victim's Spirit, the victim is transformed, taking the form and abilities of a ${this.targetActor.name} but retaining their ${this.data.critfail ? '' : 'Smarts and '}Spirit. `; if (this.data.critfail) { desc += `The victim believes they are the animal for the duration of the power.`; } desc += `
The victim may attempt to shake off the effect with a Spirit roll at ${this.data.raise ? -4 : -2} at the end of subsequent turns.`; return desc; } get primaryEffectButtons() { const buttons = super.primaryEffectButtons; const modvalue = this.data.raise ? -4 : -2; const mods = []; mods.push({ label: 'Strong', value: modvalue }); buttons.push({ label: `Shake off (Spirit ${modvalue})`, type: 'trait', rollType: 'attribute', rollDesc: 'Spirit', flavor: 'Success shakes off the effects of sloth', mods, }); return buttons; } }