mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 22:46:12 +01:00
Merged with main
This commit is contained in:
commit
b7c2d40d7f
62 changed files with 990 additions and 514 deletions
|
|
@ -30,7 +30,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
|
|||
static PARTS = {
|
||||
costSelection: {
|
||||
id: 'costSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/costSelection.hbs'
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,12 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
id: 'roll-selection',
|
||||
classes: ['daggerheart', 'views', 'roll-selection'],
|
||||
classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'roll-selection'],
|
||||
position: {
|
||||
width: 400,
|
||||
height: 'auto'
|
||||
width: 550
|
||||
},
|
||||
window: {
|
||||
icon: 'fa-solid fa-dice'
|
||||
},
|
||||
actions: {
|
||||
updateIsAdvantage: this.updateIsAdvantage,
|
||||
|
|
@ -37,20 +39,29 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
};
|
||||
|
||||
get title() {
|
||||
return this.config.title;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
costSelection: {
|
||||
id: 'costSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/costSelection.hbs'
|
||||
header: {
|
||||
id: 'header',
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/header.hbs'
|
||||
},
|
||||
rollSelection: {
|
||||
id: 'rollSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/rollSelection.hbs'
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/rollSelection.hbs'
|
||||
},
|
||||
costSelection: {
|
||||
id: 'costSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.rollConfig = this.config;
|
||||
context.hasRoll = !!this.config.roll;
|
||||
context.roll = this.roll;
|
||||
context.rollType = this.roll?.constructor.name;
|
||||
|
|
@ -60,6 +71,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}));
|
||||
context.selectedExperiences = this.config.experiences;
|
||||
context.advantage = this.config.roll?.advantage;
|
||||
context.disadvantage = this.config.roll?.disadvantage;
|
||||
context.diceOptions = CONFIG.DH.GENERAL.diceTypes;
|
||||
context.canRoll = true;
|
||||
context.isLite = this.config.roll?.lite;
|
||||
|
|
@ -75,7 +87,6 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
}
|
||||
context.extraFormula = this.config.extraFormula;
|
||||
context.formula = this.roll.constructFormula(this.config);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -96,6 +107,9 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
|||
|
||||
static updateIsAdvantage(_, button) {
|
||||
const advantage = Number(button.dataset.advantage);
|
||||
this.advantage = advantage === 1;
|
||||
this.disadvantage = advantage === -1;
|
||||
|
||||
this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage;
|
||||
this.render();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
|||
static PARTS = {
|
||||
damageSelection: {
|
||||
id: 'damageSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/damageSelection.hbs'
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/damageSelection.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
|
|||
static PARTS = {
|
||||
damageSelection: {
|
||||
id: 'damageSelection',
|
||||
template: 'systems/daggerheart/templates/dialogs/damageSelection.hbs'
|
||||
template: 'systems/daggerheart/templates/dialogs/dice-roll/damageSelection.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
static async reactionRoll(event) {
|
||||
const config = {
|
||||
event: event,
|
||||
title: `${this.actor.name} - Reaction Roll`,
|
||||
title: `Reaction Roll: ${this.actor.name}`,
|
||||
headerTitle: 'Adversary Reaction Roll',
|
||||
roll: {
|
||||
// modifier: null,
|
||||
type: 'reaction'
|
||||
|
|
|
|||
|
|
@ -490,6 +490,19 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
}
|
||||
}
|
||||
|
||||
static async rollAttribute(event, button) {
|
||||
const abilityLabel = game.i18n.localize(abilities[button.dataset.attribute].label);
|
||||
const config = {
|
||||
event: event,
|
||||
title: `${game.i18n.localize('DAGGERHEART.General.dualityRoll')}: ${this.actor.name}`,
|
||||
headerTitle: game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', { ability: abilityLabel }),
|
||||
roll: {
|
||||
trait: button.dataset.attribute
|
||||
}
|
||||
};
|
||||
this.document.diceRoll(config);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Filter Menus */
|
||||
/* -------------------------------------------- */
|
||||
|
|
|
|||
|
|
@ -50,13 +50,13 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
element.addEventListener('mouseenter', this.hoverAdvantage)
|
||||
);
|
||||
html.querySelectorAll('.advantage').forEach(element =>
|
||||
element.addEventListener('click', event => this.selectAdvantage.bind(this)(event, data.message))
|
||||
element.addEventListener('click', event => this.selectAdvantage.call(this, event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.ability-use-button').forEach(element =>
|
||||
element.addEventListener('click', event => this.abilityUseButton.bind(this)(event, data.message))
|
||||
element.addEventListener('click', event => this.abilityUseButton.call(this, event, data.message))
|
||||
);
|
||||
html.querySelectorAll('.action-use-button').forEach(element =>
|
||||
element.addEventListener('click', event => this.actionUseButton.bind(this)(event, data.message))
|
||||
element.addEventListener('click', event => this.actionUseButton.call(this, event, data.message))
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -229,24 +229,52 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
}
|
||||
};
|
||||
|
||||
onToggleTargets = async event => {
|
||||
/**
|
||||
* Toggle visibility of target containers.
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
onToggleTargets(event) {
|
||||
event.stopPropagation();
|
||||
$($(event.currentTarget).parent()).find('.target-container').toggleClass('hidden');
|
||||
};
|
||||
event.currentTarget.parentElement
|
||||
?.querySelectorAll('.target-container')
|
||||
.forEach(el => el.classList.toggle('hidden'));
|
||||
}
|
||||
|
||||
hoverAdvantage = event => {
|
||||
$(event.currentTarget).siblings('.advantage').toggleClass('unused');
|
||||
};
|
||||
/**
|
||||
* Highlight advantage icons on hover.
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
hoverAdvantage(event) {
|
||||
const parent = event.currentTarget.parentElement;
|
||||
if (!parent) return;
|
||||
|
||||
selectAdvantage = async (event, message) => {
|
||||
parent.querySelectorAll('.advantage').forEach(el => {
|
||||
if (el !== event.currentTarget) {
|
||||
el.classList.toggle('unused');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle selecting an advantage and disable further selection.
|
||||
* @param {MouseEvent} event
|
||||
* @param {object} message
|
||||
*/
|
||||
async selectAdvantage(event, message) {
|
||||
event.stopPropagation();
|
||||
|
||||
const updateMessage = game.messages.get(message._id);
|
||||
await updateMessage.update({ system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 } });
|
||||
await updateMessage?.update({
|
||||
system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 }
|
||||
});
|
||||
|
||||
$(event.currentTarget).siblings('.advantage').off('click');
|
||||
$(event.currentTarget).off('click');
|
||||
};
|
||||
const parent = event.currentTarget.parentElement;
|
||||
if (!parent) return;
|
||||
|
||||
parent.querySelectorAll('.advantage').forEach(el => {
|
||||
el.replaceWith(el.cloneNode(true));
|
||||
});
|
||||
}
|
||||
|
||||
abilityUseButton = async (event, message) => {
|
||||
event.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
export { default as FilterMenu } from './filter-menu.mjs';
|
||||
export { default as ContextMenu } from './contextMenu.mjs';
|
||||
export { default as DHContextMenu } from './contextMenu.mjs';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,63 @@
|
|||
export default class DhContextMenu extends foundry.applications.ux.ContextMenu.implementation {
|
||||
/**
|
||||
* @typedef ContextMenuEntry
|
||||
* @property {string} name The context menu label. Can be localized.
|
||||
* @property {string} [icon] A string containing an HTML icon element for the menu item.
|
||||
* @property {string} [classes] Additional CSS classes to apply to this menu item.
|
||||
* @property {string} [group] An identifier for a group this entry belongs to.
|
||||
* @property {ContextMenuJQueryCallback} callback The function to call when the menu item is clicked.
|
||||
* @property {ContextMenuCondition|boolean} [condition] A function to call or boolean value to determine if this entry
|
||||
* appears in the menu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ContextMenuCondition
|
||||
* @param {jQuery|HTMLElement} html The element of the context menu entry.
|
||||
* @returns {boolean} Whether the entry should be rendered in the context menu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ContextMenuCallback
|
||||
* @param {HTMLElement} target The element that the context menu has been triggered for.
|
||||
* @returns {unknown}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ContextMenuJQueryCallback
|
||||
* @param {HTMLElement|jQuery} target The element that the context menu has been triggered for. Will
|
||||
* either be a jQuery object or an HTMLElement instance, depending
|
||||
* on how the ContextMenu was configured.
|
||||
* @returns {unknown}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ContextMenuOptions
|
||||
* @property {string} [eventName="contextmenu"] Optionally override the triggering event which can spawn the menu. If
|
||||
* the menu is using fixed positioning, this event must be a MouseEvent.
|
||||
* @property {ContextMenuCallback} [onOpen] A function to call when the context menu is opened.
|
||||
* @property {ContextMenuCallback} [onClose] A function to call when the context menu is closed.
|
||||
* @property {boolean} [fixed=false] If true, the context menu is given a fixed position rather than being
|
||||
* injected into the target.
|
||||
* @property {boolean} [jQuery=true] If true, callbacks will be passed jQuery objects instead of HTMLElement
|
||||
* instances.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ContextMenuRenderOptions
|
||||
* @property {Event} [event] The event that triggered the context menu opening.
|
||||
* @property {boolean} [animate=true] Animate the context menu opening.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A subclass of ContextMenu.
|
||||
* @extends {foundry.applications.ux.ContextMenu}
|
||||
*/
|
||||
export default class DHContextMenu extends foundry.applications.ux.ContextMenu {
|
||||
/**
|
||||
* @param {HTMLElement|jQuery} container - The HTML element that contains the context menu targets.
|
||||
* @param {string} selector - A CSS selector which activates the context menu.
|
||||
* @param {ContextMenuEntry[]} menuItems - An Array of entries to display in the menu
|
||||
* @param {ContextMenuOptions} [options] - Additional options to configure the context menu.
|
||||
*/
|
||||
constructor(container, selector, menuItems, options) {
|
||||
super(container, selector, menuItems, options);
|
||||
|
||||
|
|
@ -6,12 +65,21 @@ export default class DhContextMenu extends foundry.applications.ux.ContextMenu.i
|
|||
this.#jQuery = options.jQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to pass jQuery objects or HTMLElement instances to callback.
|
||||
* @type {boolean}
|
||||
*/
|
||||
#jQuery;
|
||||
|
||||
/**@inheritdoc */
|
||||
activateListeners(menu) {
|
||||
menu.addEventListener('click', this.#onClickItem.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle click events on context menu items.
|
||||
* @param {PointerEvent} event The click event
|
||||
*/
|
||||
#onClickItem(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
|
@ -22,6 +90,12 @@ export default class DhContextMenu extends foundry.applications.ux.ContextMenu.i
|
|||
this.close();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Trigger a context menu event in response to a normal click on a additional options button.
|
||||
* @param {PointerEvent} event
|
||||
*/
|
||||
static triggerContextMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -197,11 +197,9 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
|
|||
}
|
||||
}));
|
||||
|
||||
return [
|
||||
...game.i18n.sortObjects(typesFilters, 'name'),
|
||||
...game.i18n.sortObjects(burdenFilter, 'name'),
|
||||
...game.i18n.sortObjects(damageTypeFilter, 'name')
|
||||
];
|
||||
const sort = arr => game.i18n.sortObjects(arr, 'name');
|
||||
|
||||
return [...sort(typesFilters, 'name'), ...sort(burdenFilter, 'name'), ...sort(damageTypeFilter, 'name')];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -244,7 +244,6 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
}
|
||||
|
||||
if (this.hasRoll) {
|
||||
console.log(config);
|
||||
const rollConfig = this.prepareRoll(config);
|
||||
config.roll = rollConfig;
|
||||
config = await this.actor.diceRoll(config);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { actionsTypes } from '../action/_module.mjs';
|
||||
|
||||
/**
|
||||
* Describes metadata about the item data model type
|
||||
* @typedef {Object} ItemDataModelMetadata
|
||||
|
|
@ -55,23 +53,27 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
return data;
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
async _preCreate(data, options, user) {
|
||||
// Skip if no initial action is required or actions already exist
|
||||
if (!this.constructor.metadata.hasInitialAction || !foundry.utils.isEmpty(this.actions)) return;
|
||||
const actionType = {
|
||||
weapon: 'attack'
|
||||
}[this.constructor.metadata.type],
|
||||
cls = actionsTypes[actionType],
|
||||
action = new cls(
|
||||
{
|
||||
_id: foundry.utils.randomID(),
|
||||
type: actionType,
|
||||
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
|
||||
...cls.getSourceConfig(this.parent)
|
||||
},
|
||||
{
|
||||
parent: this.parent
|
||||
}
|
||||
);
|
||||
|
||||
const metadataType = this.constructor.metadata.type;
|
||||
const actionType = { weapon: 'attack' }[metadataType];
|
||||
const ActionClass = game.system.api.models.actions.actionsTypes[actionType];
|
||||
|
||||
const action = new ActionClass(
|
||||
{
|
||||
_id: foundry.utils.randomID(),
|
||||
type: actionType,
|
||||
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
|
||||
...ActionClass.getSourceConfig(this.parent)
|
||||
},
|
||||
{
|
||||
parent: this.parent
|
||||
}
|
||||
);
|
||||
|
||||
this.updateSource({ actions: [action] });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,49 +7,11 @@ export default class RegisterHandlebarsHelpers {
|
|||
join: this.join,
|
||||
add: this.add,
|
||||
subtract: this.subtract,
|
||||
objectSelector: this.objectSelector,
|
||||
includes: this.includes,
|
||||
debug: this.debug,
|
||||
signedNumber: this.signedNumber,
|
||||
length: this.length,
|
||||
switch: this.switch,
|
||||
case: this.case,
|
||||
eq: this.eq,
|
||||
ne: this.ne,
|
||||
lt: this.lt,
|
||||
gt: this.gt,
|
||||
lte: this.lte,
|
||||
gte: this.gte,
|
||||
and: this.and,
|
||||
or: this.or
|
||||
case: this.case
|
||||
});
|
||||
}
|
||||
|
||||
static eq(v1, v2) {
|
||||
return v1 === v2;
|
||||
}
|
||||
static ne(v1, v2) {
|
||||
return v1 !== v2;
|
||||
}
|
||||
static lt(v1, v2) {
|
||||
return v1 < v2;
|
||||
}
|
||||
static gt(v1, v2) {
|
||||
return v1 > v2;
|
||||
}
|
||||
static lte(v1, v2) {
|
||||
return v1 <= v2;
|
||||
}
|
||||
static gte(v1, v2) {
|
||||
return v1 >= v2;
|
||||
}
|
||||
static and() {
|
||||
return Array.prototype.every.call(arguments, Boolean);
|
||||
}
|
||||
static or() {
|
||||
return Array.prototype.slice.call(arguments, 0, -1).some(Boolean);
|
||||
}
|
||||
|
||||
static times(nr, block) {
|
||||
var accum = '';
|
||||
for (var i = 0; i < nr; ++i) accum += block.fn(i);
|
||||
|
|
@ -72,69 +34,14 @@ export default class RegisterHandlebarsHelpers {
|
|||
return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum);
|
||||
}
|
||||
|
||||
static objectSelector(options) {
|
||||
let { title, values, titleFontSize, ids, style } = options.hash;
|
||||
|
||||
const titleLength = getWidthOfText(title, titleFontSize, true, true);
|
||||
const margins = 12;
|
||||
|
||||
const buttons = options.fn();
|
||||
const nrButtons = Math.max($(buttons).length - 1, 1);
|
||||
const iconWidth = 26;
|
||||
|
||||
const texts = values
|
||||
.reduce((acc, x, index) => {
|
||||
if (x) {
|
||||
acc.push(
|
||||
`<span class="object-select-item" data-action="viewObject" data-value="${ids[index]}">${x}</span>`
|
||||
);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, [])
|
||||
.join(' ');
|
||||
|
||||
const html = `<div ${style ? 'style="' + style + '"' : ''}">
|
||||
<div class="object-select-display iconbar">
|
||||
<span class="object-select-title">${title}</span>
|
||||
<div class="object-select-text" style="padding-left: ${titleLength + margins}px; padding-right: ${nrButtons * iconWidth}px;">
|
||||
${texts}
|
||||
</div>
|
||||
${buttons}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return new Handlebars.SafeString(html);
|
||||
}
|
||||
|
||||
static includes(list, item) {
|
||||
return list.includes(item);
|
||||
}
|
||||
|
||||
static signedNumber(number) {
|
||||
return number >= 0 ? `+${number}` : number;
|
||||
}
|
||||
|
||||
static length(obj) {
|
||||
return Object.keys(obj).length;
|
||||
}
|
||||
|
||||
static switch(value, options) {
|
||||
this.switch_value = value;
|
||||
this.switch_break = false;
|
||||
return options.fn(this);
|
||||
}
|
||||
|
||||
static case(value, options) {
|
||||
if (value == this.switch_value) {
|
||||
this.switch_break = true;
|
||||
return options.fn(this);
|
||||
}
|
||||
}
|
||||
|
||||
static debug(a) {
|
||||
console.log(a);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue