/* globals Sequencer */ import { log, moduleName } from '../globals.js'; import { templates } from '../preloadTemplates.js'; import { ActorFolderEffect } from './basePowers.js'; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; export class BaseSummonEffect extends ActorFolderEffect { get name() { return 'Base Summon'; } get actorFolderBase() { return 'Summonables'; } get summonCount() { return 0; } get spawnUpdates() { const updates = super.spawnUpdates; const actorUpdates = { system: { initiative: { follow: this.source.name, }, }, }; foundry.utils.mergeObject(updates.actor, actorUpdates); return updates; } async parseValuesPre() {} async parseValuesMid() {} async parseValuesPost() {} async parseValues() { await super.parseValues(); await this.parseValuesPre(); await this.parseValuesMid(); await this.parseValuesPost(); } async spawn() { const location = await Sequencer.Crosshair.show({ distance: this.targetTokenDoc.height / 2, texture: this.targetTokenDoc.texture.src, snap: { position: CONST.GRID_SNAPPING_MODES.VERTEX | CONST.GRID_SNAPPING_MODES.CENTER, }, label: { text: this.targetTokenDoc.name }, }); const tokenDocs = []; for (let i = 0; i < this.summonCount; i++) { tokenDocs[i] = this.targetTokenDoc.clone({ x: location.token.x + i * 5, y: location.token.y + i * 5, elevation: this.source.elevation, }); } log('token docs', tokenDocs); const spawned = await this.source.scene.createEmbeddedDocuments('Token', tokenDocs); log('Spawned', spawned); return spawned; } async apply() { await super.apply(); const maintainDoc = await this.createMaintainEffect(this.data.maintId); maintainDoc.flags[moduleName].targetIds = this.data.spawned.map((t) => t.id); if (this.duration > 0) { await this.applyActiveEffects(this.source, [maintainDoc]); } } } export class SummonCostApplication extends HandlebarsApplicationMixin(ApplicationV2) { constructor(actors, powers) { super(); this.actors = actors; this.powers = powers; this.object = {}; } static DEFAULT_OPTIONS = { id: 'mbSwadeSummonCostApplication', form: { handler: SummonCostApplication.#onSubmit, closeOnSubmit: true, }, tag: 'form', position: { width: 800, height: 'auto', }, classes: ['mbSwade', 'mbSwadeForm', 'mbSwadeSummonCostForm'], window: { title: 'Set Summoning Costs', }, }; static PARTS = { header: { template: templates['dialogHeader.html'], classes: ['mbSwade', 'mbSwadeDialogHeader', 'mbSwadeSummonCostsHeader'], }, body: { template: templates['summonCosts.html'], classes: ['mbSwade', 'mbSwadePowerEffectsBody', 'scrollable'], }, footer: { template: 'templates/generic/form-footer.hbs', }, }; async _prepareContext() { const actorNames = Object.keys(this.actors).map((k) => { let splitName = k.split(' | '); splitName.pop(); let folder = splitName.length ? splitName.join(' | ') : ''; return { name: this.actors[k].name, folder, fullName: k }; }); actorNames.sort((a, b) => { if (a.name < b.name) { return -1; } else if (a.name > b.name) { return 1; } return 0; }); const data = { name: 'Set Summon Costs', formId: foundry.utils.randomID(), headerTitle: 'Set Summon Costs', powers: this.powers, actors: [], buttons: [ { type: 'submit', icon: 'fa-solid fa-save', label: 'SETTINGS.Save' }, { type: 'cancel', icon: 'fa-solid fa-ban', label: 'SETTINGS.Cancel' }, ], }; for (const actor of actorNames) { const summon = this.actors[actor.fullName].getFlag(moduleName, 'summonData') ?? { cost: 0, powers: {}, }; const hbSummon = { cost: summon.cost, powers: [], }; for (const power of this.powers) { hbSummon.powers.push({ power, value: summon.powers?.[power] ?? false }); } data.actors.push({ actor, summon: hbSummon }); } log('summon data'); log(data); return data; } static async #onSubmit(event, form, formData) { const submit = event?.submitter?.value ?? 'cancel'; if (submit === 'cancel') { return; } log('FORMDATA |', formData); formData = formData.object; const updates = {}; for (const key of Object.keys(formData)) { const value = formData[key]; const [name, subKey] = key.split(':;:'); if (!(name in updates)) { updates[name] = { powers: {} }; } if (subKey === 'cost') { updates[name].cost = value; } else { updates[name].powers[subKey] = value; } } log('FORMUPDATES |', updates); for (const key of Object.keys(updates)) { const update = updates[key]; const flagValue = this.actors[key].getFlag(moduleName, 'summonData') ?? {}; foundry.utils.mergeObject(flagValue, update); const result = this.actors[key].setFlag(moduleName, 'summonData', flagValue); console.log('update', key, result); } } } export async function setSummonCosts(powers = [], folderName = null) { if (!folderName) { folderName = 'Summonables/Creatures'; } const folder = ActorFolderEffect.getPackFolderByPath(folderName); if (!folder) { log(`ERROR: Could not find folder ${folderName}`); } const indexActors = ActorFolderEffect.getPackActorsInFolder(folder); const actors = {}; const promises = []; for (const actorName in indexActors) { promises.push(foundry.utils.fromUuid(indexActors[actorName].uuid).then((result) => (actors[actorName] = result))); } await Promise.all(promises); new SummonCostApplication(actors, powers).render(true); }