mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 07:59:03 +01:00
Merge branch 'main' into feature/Character-Setup-Rework
This commit is contained in:
commit
8079dec639
42 changed files with 752 additions and 66 deletions
|
|
@ -1,5 +1,6 @@
|
|||
export * as characterCreation from './characterCreation/_module.mjs';
|
||||
export * as dialogs from './dialogs/_module.mjs';
|
||||
export * as hud from './hud/_module.mjs';
|
||||
export * as levelup from './levelup/_module.mjs';
|
||||
export * as settings from './settings/_module.mjs';
|
||||
export * as sheets from './sheets/_module.mjs';
|
||||
|
|
|
|||
1
module/applications/hud/_module.mjs
Normal file
1
module/applications/hud/_module.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default as DHTokenHUD } from './tokenHud.mjs';
|
||||
84
module/applications/hud/tokenHUD.mjs
Normal file
84
module/applications/hud/tokenHUD.mjs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
export default class DHTokenHUD extends TokenHUD {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['daggerheart']
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
hud: {
|
||||
root: true,
|
||||
template: 'systems/daggerheart/templates/hud/tokenHUD.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.systemStatusEffects = Object.keys(context.statusEffects).reduce((acc, key) => {
|
||||
const effect = context.statusEffects[key];
|
||||
if (effect.systemEffect) acc[key] = effect;
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const useGeneric = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.appearance
|
||||
).showGenericStatusEffects;
|
||||
context.genericStatusEffects = useGeneric
|
||||
? Object.keys(context.statusEffects).reduce((acc, key) => {
|
||||
const effect = context.statusEffects[key];
|
||||
if (!effect.systemEffect) acc[key] = effect;
|
||||
|
||||
return acc;
|
||||
}, {})
|
||||
: null;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
_getStatusEffectChoices() {
|
||||
// Include all HUD-enabled status effects
|
||||
const choices = {};
|
||||
for (const status of CONFIG.statusEffects) {
|
||||
if (
|
||||
status.hud === false ||
|
||||
(foundry.utils.getType(status.hud) === 'Object' &&
|
||||
status.hud.actorTypes?.includes(this.document.actor.type) === false)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
choices[status.id] = {
|
||||
_id: status._id,
|
||||
id: status.id,
|
||||
systemEffect: status.systemEffect,
|
||||
title: game.i18n.localize(status.name ?? /** @deprecated since v12 */ status.label),
|
||||
src: status.img ?? /** @deprecated since v12 */ status.icon,
|
||||
isActive: false,
|
||||
isOverlay: false
|
||||
};
|
||||
}
|
||||
|
||||
// Update the status of effects which are active for the token actor
|
||||
const activeEffects = this.actor?.effects || [];
|
||||
for (const effect of activeEffects) {
|
||||
for (const statusId of effect.statuses) {
|
||||
const status = choices[statusId];
|
||||
if (!status) continue;
|
||||
if (status._id) {
|
||||
if (status._id !== effect.id) continue;
|
||||
} else {
|
||||
if (effect.statuses.size !== 1) continue;
|
||||
}
|
||||
status.isActive = true;
|
||||
if (effect.getFlag('core', 'overlay')) status.isOverlay = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flag status CSS class
|
||||
for (const status of Object.values(choices)) {
|
||||
status.cssClass = [status.isActive ? 'active' : null, status.isOverlay ? 'overlay' : null].filterJoin(' ');
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ export default class AdversarySheet extends DHBaseActorSheet {
|
|||
actions: {
|
||||
reactionRoll: AdversarySheet.#reactionRoll,
|
||||
useItem: this.useItem,
|
||||
useAction: this.useItem,
|
||||
toChat: this.toChat
|
||||
},
|
||||
window: {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
levelManagement: CharacterSheet.#levelManagement,
|
||||
toggleEquipItem: CharacterSheet.#toggleEquipItem,
|
||||
useItem: this.useItem, //TODO Fix this
|
||||
useAction: this.useAction,
|
||||
toChat: this.toChat
|
||||
},
|
||||
window: {
|
||||
|
|
@ -620,6 +621,20 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use an action
|
||||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async useAction(event, button) {
|
||||
const item = this.getItem(button);
|
||||
if (!item) return;
|
||||
|
||||
const action = item.system.actions.find(x => x.id === button.dataset.actionId);
|
||||
if (!action) return;
|
||||
|
||||
action.use(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send item to Chat
|
||||
* @type {ApplicationClickAction}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export default class DhpEnvironment extends DHBaseActorSheet {
|
|||
},
|
||||
actions: {
|
||||
useItem: this.useItem,
|
||||
useAction: this.useItem,
|
||||
toChat: this.toChat
|
||||
},
|
||||
dragDrop: [{ dragSelector: '.action-section .inventory-item', dropSelector: null }]
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export const adversaryTypes = {
|
|||
},
|
||||
social: {
|
||||
id: 'social',
|
||||
label: 'DAGGERHEART.CONFIG.AdversaryTypee.social.label',
|
||||
label: 'DAGGERHEART.CONFIG.AdversaryType.social.label',
|
||||
description: 'DAGGERHEART.ACTORS.Adversary.social.description'
|
||||
},
|
||||
solo: {
|
||||
|
|
|
|||
|
|
@ -180,8 +180,8 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
|||
const actorData = this.actor.getRollData(false);
|
||||
|
||||
// Remove when included directly in Actor getRollData
|
||||
actorData.prof = actorData.proficiency?.value ?? 1;
|
||||
actorData.cast = actorData.spellcast?.value ?? 1;
|
||||
actorData.prof = actorData.proficiency?.total ?? 1;
|
||||
actorData.cast = actorData.spellcast?.total ?? 1;
|
||||
actorData.result = data.roll?.total ?? 1;
|
||||
/* actorData.scale = data.costs?.length
|
||||
? data.costs.reduce((a, c) => {
|
||||
|
|
|
|||
|
|
@ -66,10 +66,9 @@ export default class DhCompanion extends BaseDataActor {
|
|||
damage: {
|
||||
parts: [
|
||||
{
|
||||
multiplier: 'flat',
|
||||
value: {
|
||||
dice: 'd6',
|
||||
multiplier: 'flat'
|
||||
multiplier: 'prof'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -87,6 +86,12 @@ export default class DhCompanion extends BaseDataActor {
|
|||
};
|
||||
}
|
||||
|
||||
get proficiency() {
|
||||
return {
|
||||
total: this.partner?.system?.proficiency?.total ?? 1
|
||||
};
|
||||
}
|
||||
|
||||
prepareBaseData() {
|
||||
const partnerSpellcastingModifier = this.partner?.system?.spellcastingModifiers?.main;
|
||||
const spellcastingModifier = this.partner?.system?.traits?.[partnerSpellcastingModifier]?.total;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,12 @@ export default class DHArmor extends BaseDataItem {
|
|||
};
|
||||
}
|
||||
|
||||
get customActions() {
|
||||
return this.actions.filter(
|
||||
action => !this.armorFeatures.some(feature => feature.actionIds.includes(action.id))
|
||||
);
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, user) {
|
||||
const allowed = await super._preUpdate(changes, options, user);
|
||||
if (allowed === false) return false;
|
||||
|
|
|
|||
|
|
@ -73,6 +73,12 @@ export default class DHWeapon extends BaseDataItem {
|
|||
return [this.attack, ...this.actions];
|
||||
}
|
||||
|
||||
get customActions() {
|
||||
return this.actions.filter(
|
||||
action => !this.weaponFeatures.some(feature => feature.actionIds.includes(action.id))
|
||||
);
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, user) {
|
||||
const allowed = await super._preUpdate(changes, options, user);
|
||||
if (allowed === false) return false;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
outline: new fields.ColorField({ required: true, initial: '#ffffff' }),
|
||||
edge: new fields.ColorField({ required: true, initial: '#000000' })
|
||||
})
|
||||
}),
|
||||
showGenericStatusEffects: new fields.BooleanField({
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.showGenericStatusEffects.label'
|
||||
})
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export default class DhRangeMeasurement extends foundry.abstract.DataModel {
|
|||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
return {
|
||||
enabled: new fields.BooleanField({ required: true, initial: false, label: 'DAGGERHEART.GENERAL.enabled' }),
|
||||
enabled: new fields.BooleanField({ required: true, initial: true, label: 'DAGGERHEART.GENERAL.enabled' }),
|
||||
melee: new fields.NumberField({ required: true, initial: 5, label: 'DAGGERHEART.CONFIG.Range.melee.name' }),
|
||||
veryClose: new fields.NumberField({
|
||||
required: true,
|
||||
|
|
|
|||
|
|
@ -2,15 +2,33 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
async activate(element, options = {}) {
|
||||
let html = options.html;
|
||||
if (element.dataset.tooltip?.startsWith('#item#')) {
|
||||
const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6));
|
||||
const splitValues = element.dataset.tooltip.slice(6).split('#action#');
|
||||
const itemUuid = splitValues[0];
|
||||
const actionId = splitValues.length > 1 ? splitValues[1] : null;
|
||||
|
||||
const baseItem = await foundry.utils.fromUuid(itemUuid);
|
||||
const item = actionId ? baseItem.system.actions.find(x => x.id === actionId) : baseItem;
|
||||
if (item) {
|
||||
const type = actionId ? 'action' : item.type;
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/${item.type}.hbs`,
|
||||
item
|
||||
`systems/daggerheart/templates/ui/tooltip/${type}.hbs`,
|
||||
{
|
||||
item: item,
|
||||
config: CONFIG.DH
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
}
|
||||
}
|
||||
|
||||
super.activate(element, { ...options, html: html });
|
||||
}
|
||||
|
||||
_determineItemTooltipDirection(element) {
|
||||
const pos = element.getBoundingClientRect();
|
||||
const dirs = this.constructor.TOOLTIP_DIRECTIONS;
|
||||
return dirs[pos.x - this.tooltip.offsetWidth < 0 ? 'DOWN' : 'LEFT'];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,49 @@
|
|||
import { getWidthOfText } from './utils.mjs';
|
||||
|
||||
export default class RegisterHandlebarsHelpers {
|
||||
static registerHelpers() {
|
||||
Handlebars.registerHelper({
|
||||
times: this.times,
|
||||
join: this.join,
|
||||
add: this.add,
|
||||
subtract: this.subtract,
|
||||
includes: this.includes,
|
||||
case: this.case
|
||||
times: this.times,
|
||||
damageFormula: this.damageFormula,
|
||||
damageSymbols: this.damageSymbols,
|
||||
tertiary: this.tertiary,
|
||||
signedNumber: this.signedNumber
|
||||
});
|
||||
}
|
||||
|
||||
static times(nr, block) {
|
||||
var accum = '';
|
||||
for (var i = 0; i < nr; ++i) accum += block.fn(i);
|
||||
return accum;
|
||||
}
|
||||
|
||||
static join(...options) {
|
||||
return options.slice(0, options.length - 1);
|
||||
}
|
||||
|
||||
static add(a, b) {
|
||||
const aNum = Number.parseInt(a);
|
||||
const bNum = Number.parseInt(b);
|
||||
return (Number.isNaN(aNum) ? 0 : aNum) + (Number.isNaN(bNum) ? 0 : bNum);
|
||||
}
|
||||
|
||||
static subtract(a, b) {
|
||||
const aNum = Number.parseInt(a);
|
||||
const bNum = Number.parseInt(b);
|
||||
return (Number.isNaN(aNum) ? 0 : aNum) - (Number.isNaN(bNum) ? 0 : bNum);
|
||||
}
|
||||
|
||||
static includes(list, item) {
|
||||
return list.includes(item);
|
||||
}
|
||||
|
||||
static case(value, options) {
|
||||
if (value == this.switch_value) {
|
||||
this.switch_break = true;
|
||||
return options.fn(this);
|
||||
}
|
||||
static times(nr, block) {
|
||||
var accum = '';
|
||||
for (var i = 0; i < nr; ++i) accum += block.fn(i);
|
||||
return accum;
|
||||
}
|
||||
|
||||
static damageFormula(attack, actor) {
|
||||
const traitTotal = actor.system.traits?.[attack.roll.trait]?.total;
|
||||
const instances = [
|
||||
attack.damage.parts.map(x => Roll.replaceFormulaData(x.value.getFormula(), actor)).join(' + '),
|
||||
traitTotal
|
||||
].filter(x => x);
|
||||
|
||||
return instances.join(traitTotal > 0 ? ' + ' : ' - ');
|
||||
}
|
||||
|
||||
static damageSymbols(damageParts) {
|
||||
const symbols = new Set();
|
||||
damageParts.forEach(part => symbols.add(...CONFIG.DH.GENERAL.damageTypes[part.type].icon));
|
||||
return new Handlebars.SafeString(Array.from(symbols).map(symbol => `<i class="fa-solid ${symbol}"></i>`));
|
||||
}
|
||||
|
||||
static tertiary(a, b) {
|
||||
return a ?? b;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const preloadHandlebarsTemplates = async function () {
|
|||
'systems/daggerheart/templates/actionTypes/beastform.hbs',
|
||||
'systems/daggerheart/templates/settings/components/settings-item-line.hbs',
|
||||
'systems/daggerheart/templates/ui/chat/parts/damage-chat.hbs',
|
||||
'systems/daggerheart/templates/ui/chat/parts/target-chat.hbs'
|
||||
'systems/daggerheart/templates/ui/chat/parts/target-chat.hbs',
|
||||
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs'
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const registerMenuSettings = () => {
|
|||
});
|
||||
|
||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement, {
|
||||
scope: 'client',
|
||||
scope: 'world',
|
||||
config: false,
|
||||
type: DhRangeMeasurement
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue