Merge branch 'development' into feature/313-preset-measured-templates

This commit is contained in:
Chris Ryan 2025-11-07 19:57:47 +10:00
commit bea6140c66
26 changed files with 700 additions and 154 deletions

View file

@ -164,28 +164,31 @@ export const healingTypes = {
}
};
export const defeatedConditions = {
defeated: {
id: 'defeated',
name: 'DAGGERHEART.CONFIG.Condition.defeated.name',
img: 'icons/magic/control/fear-fright-mask-orange.webp',
description: 'DAGGERHEART.CONFIG.Condition.defeated.description'
},
unconscious: {
id: 'unconscious',
name: 'DAGGERHEART.CONFIG.Condition.unconscious.name',
img: 'icons/magic/control/sleep-bubble-purple.webp',
description: 'DAGGERHEART.CONFIG.Condition.unconscious.description'
},
dead: {
id: 'dead',
name: 'DAGGERHEART.CONFIG.Condition.dead.name',
img: 'icons/magic/death/grave-tombstone-glow-teal.webp',
description: 'DAGGERHEART.CONFIG.Condition.dead.description'
}
export const defeatedConditions = () => {
const defeated = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
return {
defeated: {
id: 'defeated',
name: 'DAGGERHEART.CONFIG.Condition.defeated.name',
img: defeated.defeatedIcon,
description: 'DAGGERHEART.CONFIG.Condition.defeated.description'
},
unconscious: {
id: 'unconscious',
name: 'DAGGERHEART.CONFIG.Condition.unconscious.name',
img: defeated.unconsciousIcon,
description: 'DAGGERHEART.CONFIG.Condition.unconscious.description'
},
dead: {
id: 'dead',
name: 'DAGGERHEART.CONFIG.Condition.dead.name',
img: defeated.deadIcon,
description: 'DAGGERHEART.CONFIG.Condition.dead.description'
}
};
};
export const conditions = {
export const conditions = () => ({
vulnerable: {
id: 'vulnerable',
name: 'DAGGERHEART.CONFIG.Condition.vulnerable.name',
@ -204,8 +207,8 @@ export const conditions = {
img: 'icons/magic/control/debuff-chains-shackle-movement-red.webp',
description: 'DAGGERHEART.CONFIG.Condition.restrained.description'
},
...defeatedConditions
};
...defeatedConditions()
});
export const defaultRestOptions = {
shortRest: () => ({

View file

@ -1,9 +1,11 @@
import DHAbilityUse from './abilityUse.mjs';
import DHActorRoll from './actorRoll.mjs';
import DHSystemMessage from './systemMessage.mjs';
export const config = {
abilityUse: DHAbilityUse,
adversaryRoll: DHActorRoll,
damageRoll: DHActorRoll,
dualityRoll: DHActorRoll
dualityRoll: DHActorRoll,
systemMessage: DHSystemMessage
};

View file

@ -0,0 +1,9 @@
export default class DHSystemMessage extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
useTitle: new fields.BooleanField({ initial: true })
};
}
}

View file

@ -81,6 +81,9 @@ export default class DamageField extends fields.SchemaField {
static async applyDamage(config, targets = null, force = false) {
targets ??= config.targets.filter(target => target.hit);
if (!config.damage || !targets?.length || (!DamageField.getApplyAutomation() && !force)) return;
const targetDamage = [];
const damagePromises = [];
for (let target of targets) {
const actor = fromUuidSync(target.actorId);
if (!actor) continue;
@ -95,9 +98,45 @@ export default class DamageField extends fields.SchemaField {
});
}
if (config.hasHealing) actor.takeHealing(config.damage);
else actor.takeDamage(config.damage, config.isDirect);
if (config.hasHealing)
damagePromises.push(
actor
.takeHealing(config.damage)
.then(updates => targetDamage.push({ token: actor.token ?? actor.prototypeToken, updates }))
);
else
damagePromises.push(
actor
.takeDamage(config.damage, config.isDirect)
.then(updates => targetDamage.push({ token: actor.token ?? actor.prototypeToken, updates }))
);
}
Promise.all(damagePromises).then(async _ => {
const summaryMessageSettings = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Automation
).summaryMessages;
if (!summaryMessageSettings.damage) return;
const cls = getDocumentClass('ChatMessage');
const msg = {
type: 'systemMessage',
user: game.user.id,
speaker: cls.getSpeaker(),
title: game.i18n.localize(
`DAGGERHEART.UI.Chat.damageSummary.${config.hasHealing ? 'healingTitle' : 'title'}`
),
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/chat/damageSummary.hbs',
{
targets: targetDamage
}
)
};
cls.create(msg);
});
}
/**

View file

@ -46,17 +46,48 @@ export default class EffectsField extends fields.ArrayField {
*/
static async applyEffects(targets) {
if (!this.effects?.length || !targets?.length) return;
let effects = this.effects;
targets.forEach(async token => {
const messageTargets = [];
targets.forEach(async baseToken => {
if (this.hasSave && token.saved.success === true) effects = this.effects.filter(e => e.onSave === true);
if (!effects.length) return;
const token = canvas.tokens.get(baseToken.id);
if (!token) return;
messageTargets.push(token.document);
effects.forEach(async e => {
const actor = canvas.tokens.get(token.id)?.actor,
effect = this.item.effects.get(e._id);
if (!actor || !effect) return;
await EffectsField.applyEffect(effect, actor);
const effect = this.item.effects.get(e._id);
if (!token.actor || !effect) return;
await EffectsField.applyEffect(effect, token.actor);
});
});
if (messageTargets.length === 0) return;
const summaryMessageSettings = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Automation
).summaryMessages;
if (!summaryMessageSettings.effects) return;
const cls = getDocumentClass('ChatMessage');
const msg = {
type: 'systemMessage',
user: game.user.id,
speaker: cls.getSpeaker(),
title: game.i18n.localize('DAGGERHEART.UI.Chat.effectSummary.title'),
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/chat/effectSummary.hbs',
{
effects: this.effects.map(e => this.item.effects.get(e._id)),
targets: messageTargets
}
)
};
cls.create(msg);
}
/**

View file

@ -2,6 +2,10 @@ export default class DhAutomation extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
summaryMessages: new fields.SchemaField({
damage: new fields.BooleanField({ initial: true, label: 'DAGGERHEART.GENERAL.damage' }),
effects: new fields.BooleanField({ initial: true, label: 'DAGGERHEART.GENERAL.Effect.plural' })
}),
hopeFear: new fields.SchemaField({
gm: new fields.BooleanField({
required: true,
@ -64,21 +68,39 @@ export default class DhAutomation extends foundry.abstract.DataModel {
}),
characterDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.unconscious.id,
choices: () => CONFIG.DH.GENERAL.defeatedConditions(),
initial: 'unconscious',
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
}),
adversaryDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
choices: () => CONFIG.DH.GENERAL.defeatedConditions(),
initial: 'defeated',
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.adversaryDefault.label'
}),
companionDefault: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.defeatedConditions,
initial: CONFIG.DH.GENERAL.defeatedConditions.defeated.id,
choices: () => CONFIG.DH.GENERAL.defeatedConditions(),
initial: 'defeated',
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
}),
deadIcon: new fields.FilePathField({
initial: 'icons/magic/death/grave-tombstone-glow-teal.webp',
categories: ['IMAGE'],
base64: false,
label: 'Dead'
}),
defeatedIcon: new fields.FilePathField({
initial: 'icons/magic/control/fear-fright-mask-orange.webp',
categories: ['IMAGE'],
base64: false,
label: 'Defeated'
}),
unconsciousIcon: new fields.FilePathField({
initial: 'icons/magic/control/sleep-bubble-purple.webp',
categories: ['IMAGE'],
base64: false,
label: 'Unconcious'
})
}),
roll: new fields.SchemaField({

View file

@ -599,6 +599,8 @@ export default class DhpActor extends Actor {
await this.modifyResource(updates);
if (Hooks.call(`${CONFIG.DH.id}.postTakeDamage`, this, updates) === false) return null;
return updates;
}
calculateDamage(baseDamage, type) {
@ -647,6 +649,8 @@ export default class DhpActor extends Actor {
await this.modifyResource(updates);
if (Hooks.call(`${CONFIG.DH.id}.postTakeHealing`, this, updates) === false) return null;
return updates;
}
async modifyResource(resources) {
@ -749,7 +753,7 @@ export default class DhpActor extends Actor {
async toggleDefeated(defeatedState) {
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions;
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions();
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
if (!defeatedState) {
for (let defeatedId of defeatedConditions) {

View file

@ -143,6 +143,12 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
html.querySelectorAll('.button-target-selection').forEach(element => {
element.addEventListener('click', this.onTargetSelection.bind(this));
});
html.querySelectorAll('.token-target-container').forEach(element => {
element.addEventListener('pointerover', this.hoverTarget);
element.addEventListener('pointerout', this.unhoverTarget);
element.addEventListener('click', this.clickTarget);
});
}
async onRollDamage(event) {

View file

@ -14,7 +14,8 @@ export default class RegisterHandlebarsHelpers {
getProperty: foundry.utils.getProperty,
setVar: this.setVar,
empty: this.empty,
pluralize: this.pluralize
pluralize: this.pluralize,
positive: this.positive
});
}
static add(a, b) {
@ -89,4 +90,8 @@ export default class RegisterHandlebarsHelpers {
const key = isSingular ? `${baseKey}.single` : `${baseKey}.plural`;
return game.i18n.localize(key);
}
static positive(a) {
return Math.abs(Number(a));
}
}

View file

@ -1,5 +1,6 @@
export const preloadHandlebarsTemplates = async function () {
foundry.applications.handlebars.loadTemplates({
'daggerheart.inventory-item-compact': 'systems/daggerheart/templates/sheets/global/partials/inventory-item-compact.hbs',
'daggerheart.inventory-items':
'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items-V2.hbs',
'daggerheart.inventory-item': 'systems/daggerheart/templates/sheets/global/partials/inventory-item-V2.hbs'
@ -29,7 +30,6 @@ export const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs',
'systems/daggerheart/templates/dialogs/downtime/activities.hbs',
'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs',
'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs',
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',