swade-mb-helpers/src/module/powers/summonSupport.js

212 lines
5.8 KiB
JavaScript

/* 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);
}