mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
349 lines
13 KiB
JavaScript
349 lines
13 KiB
JavaScript
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
|
|
|
export default class BeastformDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
|
constructor(configData, item) {
|
|
super();
|
|
|
|
this.item = item;
|
|
|
|
this.configData = configData;
|
|
this.selected = null;
|
|
this.evolved = { form: null };
|
|
this.hybrid = { forms: {}, advantages: {}, features: {} };
|
|
|
|
this._dragDrop = this._createDragDropHandlers();
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
tag: 'form',
|
|
classes: ['daggerheart', 'views', 'dialog', 'dh-style', 'beastform-selection'],
|
|
position: {
|
|
width: 600,
|
|
height: 'auto'
|
|
},
|
|
window: {
|
|
icon: 'fa-solid fa-paw'
|
|
},
|
|
actions: {
|
|
selectBeastform: this.selectBeastform,
|
|
toggleHybridFeature: this.toggleHybridFeature,
|
|
toggleHybridAdvantage: this.toggleHybridAdvantage,
|
|
submitBeastform: this.submitBeastform
|
|
},
|
|
form: {
|
|
handler: this.updateBeastform,
|
|
submitOnChange: true,
|
|
submitOnClose: false
|
|
},
|
|
dragDrop: [{ dragSelector: '.beastform-container', dropSelector: '.advanced-form-container' }]
|
|
};
|
|
|
|
get title() {
|
|
return this.item.name;
|
|
}
|
|
|
|
/** @override */
|
|
static PARTS = {
|
|
header: { template: 'systems/daggerheart/templates/dialogs/beastform/header.hbs' },
|
|
tabs: { template: 'systems/daggerheart/templates/dialogs/beastform/tabs.hbs' },
|
|
beastformTier: { template: 'systems/daggerheart/templates/dialogs/beastform/beastformTier.hbs' },
|
|
advanced: { template: 'systems/daggerheart/templates/dialogs/beastform/advanced.hbs' },
|
|
footer: { template: 'systems/daggerheart/templates/dialogs/beastform/footer.hbs' }
|
|
};
|
|
|
|
/** @inheritdoc */
|
|
static TABS = {
|
|
primary: {
|
|
tabs: [{ id: '1' }, { id: '2' }, { id: '3' }, { id: '4' }],
|
|
initial: '1',
|
|
labelPrefix: 'DAGGERHEART.GENERAL.Tiers'
|
|
}
|
|
};
|
|
|
|
changeTab(tab, group, options) {
|
|
super.changeTab(tab, group, options);
|
|
|
|
this.render();
|
|
}
|
|
|
|
_createDragDropHandlers() {
|
|
return this.options.dragDrop.map(d => {
|
|
d.callbacks = {
|
|
dragstart: this._onDragStart.bind(this),
|
|
drop: this._onDrop.bind(this)
|
|
};
|
|
return new foundry.applications.ux.DragDrop.implementation(d);
|
|
});
|
|
}
|
|
|
|
_attachPartListeners(partId, htmlElement, options) {
|
|
super._attachPartListeners(partId, htmlElement, options);
|
|
|
|
this._dragDrop.forEach(d => d.bind(htmlElement));
|
|
}
|
|
|
|
async _prepareContext(_options) {
|
|
const context = await super._prepareContext(_options);
|
|
|
|
context.selected = this.selected;
|
|
context.selectedBeastformEffect = this.selected?.effects?.find?.(x => x.type === 'beastform');
|
|
|
|
context.evolved = this.evolved;
|
|
|
|
context.hybridForms = Object.keys(this.hybrid.forms).reduce((acc, formKey) => {
|
|
if (!this.hybrid.forms[formKey]) {
|
|
acc[formKey] = null;
|
|
} else {
|
|
const data = this.hybrid.forms[formKey].toObject();
|
|
acc[formKey] = {
|
|
...data,
|
|
system: {
|
|
...data.system,
|
|
features: this.hybrid.forms[formKey].system.features.map(feature => ({
|
|
...feature.toObject(),
|
|
uuid: feature.uuid,
|
|
selected: Boolean(this.hybrid.features?.[formKey]?.[feature.uuid])
|
|
})),
|
|
advantageOn: Object.keys(data.system.advantageOn).reduce((acc, key) => {
|
|
acc[key] = {
|
|
...data.system.advantageOn[key],
|
|
selected: Boolean(this.hybrid.advantages?.[formKey]?.[key])
|
|
};
|
|
return acc;
|
|
}, {})
|
|
}
|
|
};
|
|
}
|
|
return acc;
|
|
}, {});
|
|
|
|
const maximumDragTier = Math.max(
|
|
this.selected?.system?.evolved?.maximumTier ?? 0,
|
|
this.selected?.system?.hybrid?.maximumTier ?? 0
|
|
);
|
|
|
|
const compendiumBeastforms = await game.packs.get(`daggerheart.beastforms`)?.getDocuments();
|
|
const beastformTiers = [...game.items, ...(compendiumBeastforms ? compendiumBeastforms : [])].reduce(
|
|
(acc, x) => {
|
|
const tier = CONFIG.DH.GENERAL.tiers[x.system.tier];
|
|
if (x.type !== 'beastform' || tier.id > this.configData.tierLimit) return acc;
|
|
|
|
if (!acc[tier.id]) acc[tier.id] = { label: game.i18n.localize(tier.label), values: {} };
|
|
|
|
if (Object.values(acc[tier.id].values).find(existing => existing.value.name === x.name)) return acc;
|
|
|
|
acc[tier.id].values[x.uuid] = {
|
|
selected: this.selected?.uuid == x.uuid,
|
|
value: x,
|
|
draggable:
|
|
!['evolved', 'hybrid'].includes(x.system.beastformType) && maximumDragTier
|
|
? x.system.tier <= maximumDragTier
|
|
: false
|
|
};
|
|
|
|
return acc;
|
|
},
|
|
{}
|
|
);
|
|
|
|
context.tier = beastformTiers[this.tabGroups.primary];
|
|
context.tierKey = this.tabGroups.primary;
|
|
|
|
context.canSubmit = this.canSubmit();
|
|
|
|
return context;
|
|
}
|
|
|
|
canSubmit() {
|
|
if (this.selected) {
|
|
switch (this.selected.system.beastformType) {
|
|
case 'normal':
|
|
return true;
|
|
case 'evolved':
|
|
return this.evolved.form;
|
|
case 'hybrid':
|
|
const selectedAdvantages = Object.values(this.hybrid.advantages).reduce(
|
|
(acc, form) => acc + Object.values(form).length,
|
|
0
|
|
);
|
|
const selectedFeatures = Object.values(this.hybrid.features).reduce(
|
|
(acc, form) => acc + Object.values(form).length,
|
|
0
|
|
);
|
|
|
|
const advantagesSelected = selectedAdvantages === this.selected.system.hybrid.advantages;
|
|
const featuresSelected = selectedFeatures === this.selected.system.hybrid.features;
|
|
return advantagesSelected && featuresSelected;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static updateBeastform(event, _, formData) {
|
|
this.selected = foundry.utils.mergeObject(this.selected, formData.object);
|
|
|
|
this.render();
|
|
}
|
|
|
|
static async selectBeastform(_, target) {
|
|
this.element.querySelectorAll('.beastform-container ').forEach(element => {
|
|
if (element.dataset.uuid === target.dataset.uuid && this.selected?.uuid !== target.dataset.uuid) {
|
|
element.classList.remove('inactive');
|
|
} else {
|
|
element.classList.add('inactive');
|
|
}
|
|
});
|
|
|
|
const uuid = this.selected?.uuid === target.dataset.uuid ? null : target.dataset.uuid;
|
|
this.selected = uuid ? await foundry.utils.fromUuid(uuid) : null;
|
|
|
|
if (this.selected) {
|
|
if (this.selected.system.beastformType !== 'evolved') this.evolved.form = null;
|
|
if (this.selected.system.beastformType !== 'hybrid') {
|
|
this.hybrid.forms = {};
|
|
this.hybrid.advantages = {};
|
|
this.hybrid.features = {};
|
|
} else {
|
|
this.hybrid.forms = [...Array(this.selected.system.hybrid.beastformOptions).keys()].reduce((acc, _) => {
|
|
acc[foundry.utils.randomID()] = null;
|
|
return acc;
|
|
}, {});
|
|
}
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
|
|
static toggleHybridFeature(_, button) {
|
|
const current = this.hybrid.features[button.dataset.form];
|
|
if (!current) this.hybrid.features[button.dataset.form] = {};
|
|
|
|
if (this.hybrid.features[button.dataset.form][button.id])
|
|
delete this.hybrid.features[button.dataset.form][button.id];
|
|
else {
|
|
const currentFeatures = Object.values(this.hybrid.features).reduce(
|
|
(acc, form) => acc + Object.values(form).length,
|
|
0
|
|
);
|
|
if (currentFeatures === this.selected.system.hybrid.features) {
|
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.beastformToManyFeatures'));
|
|
return;
|
|
}
|
|
|
|
const feature = this.hybrid.forms[button.dataset.form].system.features.find(x => x.uuid === button.id);
|
|
this.hybrid.features[button.dataset.form][button.id] = feature;
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
|
|
static toggleHybridAdvantage(_, button) {
|
|
const current = this.hybrid.advantages[button.dataset.form];
|
|
if (!current) this.hybrid.advantages[button.dataset.form] = {};
|
|
|
|
if (this.hybrid.advantages[button.dataset.form][button.id])
|
|
delete this.hybrid.advantages[button.dataset.form][button.id];
|
|
else {
|
|
const currentAdvantages = Object.values(this.hybrid.advantages).reduce(
|
|
(acc, form) => acc + Object.values(form).length,
|
|
0
|
|
);
|
|
if (currentAdvantages === this.selected.system.hybrid.advantages) {
|
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.beastformToManyAdvantages'));
|
|
return;
|
|
}
|
|
|
|
const advantage = this.hybrid.forms[button.dataset.form].system.advantageOn[button.id];
|
|
this.hybrid.advantages[button.dataset.form][button.id] = advantage;
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
|
|
static async submitBeastform() {
|
|
await this.close({ submitted: true });
|
|
}
|
|
|
|
/** @override */
|
|
_onClose(options = {}) {
|
|
if (!options.submitted) this.selected = null;
|
|
}
|
|
|
|
static async configure(configData, item) {
|
|
return new Promise(resolve => {
|
|
const app = new this(configData, item);
|
|
const featureItem = item;
|
|
app.addEventListener(
|
|
'close',
|
|
async () => {
|
|
const selected = app.selected.toObject();
|
|
const evolved = app.evolved.form ? app.evolved.form.toObject() : null;
|
|
const data = await game.system.api.data.items.DHBeastform.getWildcardImage(
|
|
app.configData.data.parent,
|
|
evolved ?? app.selected
|
|
);
|
|
if (data) {
|
|
if (!data.selectedImage) selected = null;
|
|
else {
|
|
const imageSource = evolved ?? selected;
|
|
if (imageSource.usesDynamicToken) imageSource.system.tokenRingImg = data.selectedImage;
|
|
else imageSource.system.tokenImg = data.selectedImage;
|
|
}
|
|
}
|
|
|
|
resolve({
|
|
selected: selected,
|
|
evolved: { ...app.evolved, form: evolved },
|
|
hybrid: app.hybrid,
|
|
item: featureItem
|
|
});
|
|
},
|
|
{ once: true }
|
|
);
|
|
app.render({ force: true });
|
|
});
|
|
}
|
|
|
|
async _onDragStart(event) {
|
|
const target = event.currentTarget;
|
|
const abort = () => event.preventDefault();
|
|
if (!this.selected) abort();
|
|
|
|
const draggedForm = await foundry.utils.fromUuid(target.dataset.uuid);
|
|
if (['evolved', 'hybrid'].includes(draggedForm.system.beastformType)) abort();
|
|
|
|
if (this.selected.system.beastformType === 'evolved') {
|
|
if (draggedForm.system.tier > this.selected.system.evolved.maximumTier) abort();
|
|
}
|
|
if (this.selected.system.beastformType === 'hybrid') {
|
|
if (draggedForm.system.tier > this.selected.system.hybrid.maximumTier) abort();
|
|
}
|
|
|
|
event.dataTransfer.setData('text/plain', JSON.stringify(target.dataset));
|
|
event.dataTransfer.setDragImage(target, 60, 0);
|
|
}
|
|
|
|
async _onDrop(event) {
|
|
event.stopPropagation();
|
|
const data = foundry.applications.ux.TextEditor.getDragEventData(event);
|
|
const item = await fromUuid(data.uuid);
|
|
if (!item) return;
|
|
|
|
if (event.target.closest('.advanced-form-container.evolved')) {
|
|
this.evolved.form = item;
|
|
} else {
|
|
const hybridContainer = event.target.closest('.advanced-form-container.hybridized');
|
|
if (hybridContainer) {
|
|
const existingId = Object.keys(this.hybrid.forms).find(
|
|
key => this.hybrid.forms[key]?.uuid === item.uuid
|
|
);
|
|
if (existingId) this.hybrid.forms[existingId] = null;
|
|
|
|
this.hybrid.forms[hybridContainer.id] = item;
|
|
}
|
|
}
|
|
|
|
this.render();
|
|
}
|
|
}
|