import { moduleName } from '../globals.js'; import { ActorFolderEffect } from './basePowers.js'; export class ShapeChangeEffect extends ActorFolderEffect { get name() { return 'Shape Change'; } 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 0; } get hasRange() { return false; } get actorFolderBase() { return 'Morphables'; } actorValue(actor) { const size = actor.system.stats.size; let value = 3; if (size >= 5) { value = 15; } else if (size >= 3) { value = 11; } else if (size >= 1) { value = 8; } else if (size >= 0) { value = 5; } return value; } get modifiers() { return [ ...super.modifiers, { name: 'Duration', type: 'checkbox', value: 1, id: 'duration', epic: false, effect: false, }, { name: 'Transform Other?', type: 'select', default: 'none', id: 'transform', epic: true, choices: { none: 'None', touch: '⭐ Transform (touch)', smarts: '⭐ Transform (smarts)', }, effects: { none: null, touch: null, smarts: null }, values: { none: 0, touch: 2, smarts: 3 }, }, ]; } async parseValues() { await super.parseValues(); this.target = this?.targets?.[0] ?? this.source; this.data.actorUpdates = { name: `${this.target.actor.name} (${this.targetActor.name} form)`, system: { wildcard: this.target.actor.system.wildcard, attributes: {}, }, }; for (const stat of ['smarts', 'spirit']) { 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.srcTokenId': this.target.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 = await this.target.actor.getEmbeddedDocument('ActiveEffect', effect.id); this.data.embeddedUpdates.ActiveEffect[effect.name] = doc; } for (const item of this.target.actor.items.filter( (i) => (i.type === 'skill' && ['smarts', 'spirit'].includes(i.system.attribute)) || ['power', 'edge', 'hindrance', 'action'].includes(i.type), )) { const doc = await this.target.actor.getEmbeddedDocument('Item', item.id); this.data.embeddedUpdates.Item[item.name] = doc; } } async spawn() { this.targetTokenDoc.updateSource({ x: this.target.x, y: this.target.y, elevation: this.target.elevation, }); return this.source.scene.createEmbeddedDocuments('Token', [this.targetTokenDoc]); } get effectName() { return `Shape Change into ${this.targetActor.prototypeToken.name}`; } getPrimaryEffectChanges() { const changes = super.getPrimaryEffectChanges(); if (this.data.raise) { for (const stat of ['vigor', 'strength']) { changes.push({ key: `system.attributes.${stat}.die.sides`, mode: CONST.ACTIVE_EFFECT_MODES.ADD, value: 2, priority: 0, }); } } return changes; } get spawnUpdates() { const updates = super.spawnUpdates; mergeObject(updates.actor, this.data.actorUpdates); mergeObject(updates.token, this.data.tokenUpdates); mergeObject(updates.embedded, this.data.embeddedUpdates); return updates; } get description() { let desc = super.description; return desc; } }