mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-17 23:49:02 +01:00
Merge branch 'main' into feature/beastform-types
This commit is contained in:
commit
9f22545f7d
29 changed files with 391 additions and 115 deletions
|
|
@ -506,9 +506,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
|||
name: this.setup.ancestryName ?? this.setup.primaryAncestry.name,
|
||||
system: {
|
||||
...this.setup.primaryAncestry.system,
|
||||
features: [primaryAncestryFeature.uuid, secondaryAncestryFeature.uuid],
|
||||
primaryFeature: primaryAncestryFeature.uuid,
|
||||
secondaryFeature: secondaryAncestryFeature.uuid
|
||||
features: [primaryAncestryFeature.uuid, secondaryAncestryFeature.uuid]
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ export default class ResourceDiceDialog extends HandlebarsApplicationMixin(Appli
|
|||
|
||||
static async rerollDice() {
|
||||
const max = itemAbleRollParse(this.item.system.resource.max, this.actor, this.item);
|
||||
const diceFormula = `${max}d${this.item.system.resource.dieFaces}`;
|
||||
const diceFormula = `${max}${this.item.system.resource.dieFaces}`;
|
||||
const roll = await new Roll(diceFormula).evaluate();
|
||||
if (game.modules.get('dice-so-nice')?.active) await game.dice3d.showForRoll(roll, game.user, true);
|
||||
this.rollValues = roll.terms[0].results.map(x => ({ value: x.result, used: false }));
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
actions: {
|
||||
openSettings: DHBaseActorSheet.#openSettings
|
||||
},
|
||||
dragDrop: []
|
||||
dragDrop: [{ dragSelector: '.inventory-item[data-type="attack"]', dropSelector: null }]
|
||||
};
|
||||
|
||||
/**@type {typeof DHBaseActorSettings}*/
|
||||
|
|
@ -49,4 +49,27 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
|||
static async #openSettings() {
|
||||
await this.settingSheet.render({ force: true });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Application Drag/Drop */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* On dragStart on the item.
|
||||
* @param {DragEvent} event - The drag event
|
||||
*/
|
||||
async _onDragStart(event) {
|
||||
const attackItem = event.currentTarget.closest('.inventory-item[data-type="attack"]');
|
||||
|
||||
if (attackItem) {
|
||||
const attackData = {
|
||||
type: 'Attack',
|
||||
actorUuid: this.document.uuid,
|
||||
img: this.document.system.attack.img,
|
||||
fromInternal: true
|
||||
};
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(attackData));
|
||||
event.dataTransfer.setDragImage(attackItem.querySelector('img'), 60, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
},
|
||||
dragDrop: [
|
||||
{ dragSelector: null, dropSelector: '.tab.features .drop-section' },
|
||||
{ dragSelector: '.feature-item', dropSelector: null }
|
||||
{ dragSelector: '.feature-item', dropSelector: null },
|
||||
{ dragSelector: '.action-item', dropSelector: null }
|
||||
]
|
||||
};
|
||||
|
||||
|
|
@ -258,6 +259,23 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
const featureData = { type: 'Item', data: { ...feature.toObject(), _id: null }, fromInternal: true };
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(featureData));
|
||||
event.dataTransfer.setDragImage(featureItem.querySelector('img'), 60, 0);
|
||||
} else {
|
||||
const actionItem = event.currentTarget.closest('.action-item');
|
||||
if (actionItem) {
|
||||
const action = this.document.system.actions[actionItem.dataset.index];
|
||||
if (!action) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.actionIsMissing'));
|
||||
return;
|
||||
}
|
||||
|
||||
const actionData = {
|
||||
type: 'Action',
|
||||
data: { ...action.toObject(), id: action.id, itemUuid: this.document.uuid },
|
||||
fromInternal: true
|
||||
};
|
||||
event.dataTransfer.setData('text/plain', JSON.stringify(actionData));
|
||||
event.dataTransfer.setDragImage(actionItem.querySelector('img'), 60, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,22 +63,8 @@ export default class AncestrySheet extends DHHeritageSheet {
|
|||
event.stopPropagation();
|
||||
const target = button.closest('.feature-item');
|
||||
const feature = this.document.system[`${target.dataset.type}Feature`];
|
||||
const featureExists = feature && Object.keys(feature).length > 0;
|
||||
|
||||
if (featureExists) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: {
|
||||
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||
type: game.i18n.localize(`TYPES.Item.feature`),
|
||||
name: feature.name
|
||||
})
|
||||
},
|
||||
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: feature.name })
|
||||
});
|
||||
if (!confirmed) return;
|
||||
}
|
||||
|
||||
if (featureExists && target.dataset.type === 'primary') await feature.update({ 'system.primary': null });
|
||||
if (feature) await feature.update({ 'system.subType': null });
|
||||
await this.document.update({
|
||||
'system.features': this.document.system.features.filter(x => x && x.uuid !== feature.uuid).map(x => x.uuid)
|
||||
});
|
||||
|
|
@ -94,15 +80,18 @@ export default class AncestrySheet extends DHHeritageSheet {
|
|||
*/
|
||||
async _onDrop(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
|
||||
const item = await fromUuid(data.uuid);
|
||||
if (item?.type === 'feature') {
|
||||
const subType = event.target.closest('.primary-feature') ? 'primary' : 'secondary';
|
||||
await item.update({ 'system.subType': subType });
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes[subType]) {
|
||||
const error = subType === 'primary' ? 'featureNotPrimary' : 'featureNotSecondary';
|
||||
ui.notifications.warn(game.i18n.localize(`DAGGERHEART.UI.Notifications.${error}`));
|
||||
return;
|
||||
}
|
||||
|
||||
await item.update({ 'system.subType': subType });
|
||||
await this.document.update({
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ export default class ClassSheet extends DHBaseItemSheet {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
async _onDrop(event) {
|
||||
event.stopPropagation();
|
||||
const data = TextEditor.getDragEventData(event);
|
||||
const item = await fromUuid(data.uuid);
|
||||
const target = event.target.closest('fieldset.drop-section');
|
||||
|
|
@ -87,12 +88,24 @@ export default class ClassSheet extends DHBaseItemSheet {
|
|||
});
|
||||
} else if (item.type === 'feature') {
|
||||
if (target.classList.contains('hope-feature')) {
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.hope) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotHope'));
|
||||
return;
|
||||
}
|
||||
|
||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.hope });
|
||||
await this.document.update({
|
||||
'system.hopeFeatures': [...this.document.system.hopeFeatures.map(x => x.uuid), item.uuid]
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
} else if (target.classList.contains('class-feature')) {
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.class) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotClass'));
|
||||
return;
|
||||
}
|
||||
|
||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.class });
|
||||
await this.document.update({
|
||||
'system.classFeatures': [...this.document.system.classFeatures.map(x => x.uuid), item.uuid]
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
}
|
||||
} else if (item.type === 'weapon') {
|
||||
|
|
@ -177,28 +190,25 @@ export default class ClassSheet extends DHBaseItemSheet {
|
|||
doc.sheet.render({ force: true });
|
||||
}
|
||||
|
||||
getActionPath(type) {
|
||||
return type === 'hope' ? 'hopeFeatures' : 'classFeatures';
|
||||
}
|
||||
|
||||
static async addFeature(_, target) {
|
||||
const actionPath = this.getActionPath(target.dataset.type);
|
||||
const feature = await game.items.documentClass.create({
|
||||
type: 'feature',
|
||||
name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize('TYPES.Item.feature') })
|
||||
name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize('TYPES.Item.feature') }),
|
||||
system: {
|
||||
subType:
|
||||
target.dataset.type === 'hope'
|
||||
? CONFIG.DH.ITEM.featureSubTypes.hope
|
||||
: CONFIG.DH.ITEM.featureSubTypes.class
|
||||
}
|
||||
});
|
||||
await this.document.update({
|
||||
[`system.${actionPath}`]: [
|
||||
...this.document.system[actionPath].filter(x => x).map(x => x.uuid),
|
||||
feature.uuid
|
||||
]
|
||||
[`system.features`]: [...this.document.system.features.filter(x => x).map(x => x.uuid), feature.uuid]
|
||||
});
|
||||
}
|
||||
|
||||
static async editFeature(_, button) {
|
||||
const target = button.closest('.feature-item');
|
||||
const actionPath = this.getActionPath(button.dataset.type);
|
||||
const feature = this.document.system[actionPath].find(x => x?.id === target.dataset.featureId);
|
||||
const feature = this.document.system.features.find(x => x?.id === target.dataset.featureId);
|
||||
if (!feature) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
||||
return;
|
||||
|
|
@ -210,10 +220,16 @@ export default class ClassSheet extends DHBaseItemSheet {
|
|||
static async deleteFeature(event, button) {
|
||||
event.stopPropagation();
|
||||
const target = button.closest('.feature-item');
|
||||
const actionPath = this.getActionPath(button.dataset.type);
|
||||
|
||||
const feature = this.document.system.features.find(
|
||||
feature => feature && feature.id === target.dataset.featureId
|
||||
);
|
||||
if (feature) {
|
||||
await feature.update({ 'system.subType': null });
|
||||
}
|
||||
|
||||
await this.document.update({
|
||||
[`system.${actionPath}`]: this.document.system[actionPath]
|
||||
[`system.features`]: this.document.system.features
|
||||
.filter(feature => feature && feature.id !== target.dataset.featureId)
|
||||
.map(x => x.uuid)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,28 +40,46 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
|||
static async addFeature(_, target) {
|
||||
const feature = await game.items.documentClass.create({
|
||||
type: 'feature',
|
||||
name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize('TYPES.Item.feature') })
|
||||
name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize('TYPES.Item.feature') }),
|
||||
system: {
|
||||
subType:
|
||||
target.dataset.type === 'foundation'
|
||||
? CONFIG.DH.ITEM.featureSubTypes.foundation
|
||||
: target.dataset.type === 'specialization'
|
||||
? CONFIG.DH.ITEM.featureSubTypes.specialization
|
||||
: CONFIG.DH.ITEM.featureSubTypes.mastery
|
||||
}
|
||||
});
|
||||
await this.document.update({
|
||||
[`system.${target.dataset.type}`]: feature.uuid
|
||||
[`system.features`]: [...this.document.system.features.map(x => x.uuid), feature.uuid]
|
||||
});
|
||||
}
|
||||
|
||||
static async editFeature(_, button) {
|
||||
const feature = this.document.system[button.dataset.type];
|
||||
const feature = this.document.system.features.find(x => x.id === button.dataset.feature);
|
||||
if (!feature) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (feature) {
|
||||
await feature.update({ 'system.subType': null });
|
||||
}
|
||||
|
||||
feature.sheet.render(true);
|
||||
}
|
||||
|
||||
static async deleteFeature(event, button) {
|
||||
static async deleteFeature(event, target) {
|
||||
event.stopPropagation();
|
||||
const feature = this.document.system.features.find(feature => feature.id === target.dataset.feature);
|
||||
if (feature) {
|
||||
await feature.update({ 'system.subType': null });
|
||||
}
|
||||
|
||||
await this.document.update({
|
||||
[`system.${button.dataset.type}`]: null
|
||||
[`system.features`]: this.document.system.features
|
||||
.filter(feature => feature && feature.id !== target.dataset.feature)
|
||||
.map(x => x.uuid)
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -82,18 +100,45 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
|||
}
|
||||
|
||||
async _onDrop(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
|
||||
if (data.fromInternal) return;
|
||||
|
||||
const item = await fromUuid(data.uuid);
|
||||
if (item?.type === 'feature') {
|
||||
const dropSection = event.target.closest('.drop-section');
|
||||
if (this.document.system[dropSection.dataset.type]) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.notifications.featureIsFull'));
|
||||
return;
|
||||
}
|
||||
const target = event.target.closest('fieldset.drop-section');
|
||||
if (item.type === 'feature') {
|
||||
if (target.dataset.type === 'foundation') {
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.foundation) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotFoundation'));
|
||||
return;
|
||||
}
|
||||
|
||||
await this.document.update({ [`system.${dropSection.dataset.type}`]: item.uuid });
|
||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.foundation });
|
||||
await this.document.update({
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
} else if (target.dataset.type === 'specialization') {
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.specialization) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotSpecialization'));
|
||||
return;
|
||||
}
|
||||
|
||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.specialization });
|
||||
await this.document.update({
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
} else if (target.dataset.type === 'mastery') {
|
||||
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.mastery) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotMastery'));
|
||||
return;
|
||||
}
|
||||
|
||||
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.mastery });
|
||||
await this.document.update({
|
||||
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ export { default as DhChatLog } from './chatLog.mjs';
|
|||
export { default as DhCombatTracker } from './combatTracker.mjs';
|
||||
export * as DhCountdowns from './countdowns.mjs';
|
||||
export { default as DhFearTracker } from './fearTracker.mjs';
|
||||
export { default as DhHotbar } from './hotbar.mjs';
|
||||
|
|
|
|||
129
module/applications/ui/hotbar.mjs
Normal file
129
module/applications/ui/hotbar.mjs
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
export default class DhHotbar extends foundry.applications.ui.Hotbar {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.setupHooks();
|
||||
}
|
||||
|
||||
static async useItem(uuid) {
|
||||
const item = await fromUuid(uuid);
|
||||
if (!item) {
|
||||
return ui.notifications.warn('WARNING.ObjectDoesNotExist', {
|
||||
format: {
|
||||
name: game.i18n.localize('Document'),
|
||||
identifier: uuid
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await item.use({});
|
||||
}
|
||||
|
||||
static async useAction(itemUuid, actionId) {
|
||||
const item = await foundry.utils.fromUuid(itemUuid);
|
||||
if (!item) {
|
||||
return ui.notifications.warn('WARNING.ObjectDoesNotExist', {
|
||||
format: {
|
||||
name: game.i18n.localize('Document'),
|
||||
identifier: itemUuid
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const action = item.system.actions.find(x => x.id === actionId);
|
||||
if (!action) {
|
||||
return ui.notifications.warn('DAGGERHEART.UI.Notifications.actionIsMissing');
|
||||
}
|
||||
|
||||
await action.use({});
|
||||
}
|
||||
|
||||
static async useAttack(actorUuid) {
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
if (!actor) {
|
||||
return ui.notifications.warn('WARNING.ObjectDoesNotExist', {
|
||||
format: {
|
||||
name: game.i18n.localize('Document'),
|
||||
identifier: actorUuid
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const attack = actor.system.attack;
|
||||
if (!attack) {
|
||||
return ui.notifications.warn('DAGGERHEART.UI.Notifications.attackIsMissing');
|
||||
}
|
||||
|
||||
await attack.use({});
|
||||
}
|
||||
|
||||
setupHooks() {
|
||||
Hooks.on('hotbarDrop', (bar, data, slot) => {
|
||||
if (data.type === 'Item') {
|
||||
const item = foundry.utils.fromUuidSync(data.uuid);
|
||||
if (item.uuid.startsWith('Compendium') || !item.isOwned || !item.isOwner) return true;
|
||||
|
||||
switch (item.type) {
|
||||
case 'ancestry':
|
||||
case 'community':
|
||||
case 'class':
|
||||
case 'subclass':
|
||||
return true;
|
||||
default:
|
||||
this.createItemMacro(item, slot);
|
||||
return false;
|
||||
}
|
||||
} else if (data.type === 'Action') {
|
||||
const item = foundry.utils.fromUuidSync(data.data.itemUuid);
|
||||
if (item.uuid.startsWith('Compendium')) return true;
|
||||
if (!item.isOwned || !item.isOwner) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.unownedActionMacro'));
|
||||
return false;
|
||||
}
|
||||
|
||||
this.createActionMacro(data, slot);
|
||||
return false;
|
||||
} else if (data.type === 'Attack') {
|
||||
const actor = foundry.utils.fromUuidSync(data.actorUuid);
|
||||
if (actor.uuid.startsWith('Compendium')) return true;
|
||||
if (!actor.isOwner) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.unownedAttackMacro'));
|
||||
return false;
|
||||
}
|
||||
|
||||
this.createAttackMacro(data, slot);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async createItemMacro(data, slot) {
|
||||
const macro = await Macro.implementation.create({
|
||||
name: `${game.i18n.localize('Display')} ${name}`,
|
||||
type: CONST.MACRO_TYPES.SCRIPT,
|
||||
img: data.img,
|
||||
command: `await game.system.api.applications.ui.DhHotbar.useItem("${data.uuid}");`
|
||||
});
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
|
||||
async createActionMacro(data, slot) {
|
||||
const macro = await Macro.implementation.create({
|
||||
name: `${game.i18n.localize('Display')} ${name}`,
|
||||
type: CONST.MACRO_TYPES.SCRIPT,
|
||||
img: data.data.img,
|
||||
command: `await game.system.api.applications.ui.DhHotbar.useAction("${data.data.itemUuid}", "${data.data.id}");`
|
||||
});
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
|
||||
async createAttackMacro(data, slot) {
|
||||
const macro = await Macro.implementation.create({
|
||||
name: `${game.i18n.localize('Display')} ${name}`,
|
||||
type: CONST.MACRO_TYPES.SCRIPT,
|
||||
img: data.img,
|
||||
command: `await game.system.api.applications.ui.DhHotbar.useAttack("${data.actorUuid}");`
|
||||
});
|
||||
await game.user.assignHotbarMacro(macro, slot);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue