[Fix] Automation Fixes (#342)

* Initial

* Split HopeFear automation by GM and Players

* Fixed ActionToken automation
This commit is contained in:
WBHarry 2025-07-15 15:59:01 +02:00 committed by GitHub
parent 0dd5b53313
commit aa2714e021
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 87 additions and 76 deletions

View file

@ -5,7 +5,7 @@ import * as documents from './module/documents/_module.mjs';
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
import { DhDualityRollEnricher, DhTemplateEnricher } from './module/enrichers/_module.mjs';
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
import { NarrativeCountdowns, registerCountdownApplicationHooks } from './module/applications/ui/countdowns.mjs';
import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs';
import { DualityRollColor } from './module/data/settings/Appearance.mjs';
import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/dice/_module.mjs';
import { renderDualityButton } from './module/enrichers/DualityRollEnricher.mjs';
@ -168,7 +168,6 @@ Hooks.on('ready', () => {
registerCountdownHooks();
socketRegistration.registerSocketHooks();
registerCountdownApplicationHooks();
registerRollDiceHooks();
registerDHActorHooks();
});

View file

@ -1337,9 +1337,10 @@
"hint": "Automatically increase the GM's fear pool on a fear duality roll result."
},
"FIELDS": {
"hope": {
"label": "Hope",
"hint": "Automatically increase a character's hope on a hope duality roll result."
"hopeFear": {
"label": "Hope & Fear",
"gm": { "label": "GM" },
"players": { "label": "Players" }
},
"actionPoints": {
"label": "Action Points",

View file

@ -1,4 +1,4 @@
export default class DHTokenHUD extends TokenHUD {
export default class DHTokenHUD extends foundry.applications.hud.TokenHUD {
static DEFAULT_OPTIONS = {
classes: ['daggerheart']
};

View file

@ -669,10 +669,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
} else if (item instanceof ActiveEffect) {
item.toChat(this);
} else {
const wasUsed = await item.use(event);
if (wasUsed && item.type === 'weapon') {
Hooks.callAll(CONFIG.DH.HOOKS.characterAttack, {});
}
item.use(event);
}
}

View file

@ -66,6 +66,11 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
}
async setCombatantSpotlight(combatantId) {
const update = {
system: {
'spotlight.requesting': false
}
};
const combatant = this.viewed.combatants.get(combatantId);
const toggleTurn = this.viewed.combatants.contents
@ -73,10 +78,18 @@ export default class DhCombatTracker extends foundry.applications.sidebar.tabs.C
.map(x => x.id)
.indexOf(combatantId);
if (this.viewed.turn !== toggleTurn) Hooks.callAll(CONFIG.DH.HOOKS.spotlight, {});
if (this.viewed.turn !== toggleTurn) {
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.spotlight.id);
const autoPoints = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).actionPoints;
if (autoPoints) {
update.system.actionTokens = Math.max(combatant.system.actionTokens - 1, 0);
}
}
await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn });
await combatant.update({ 'system.spotlight.requesting': false });
await combatant.update(update);
}
static async requestSpotlight(_, target) {

View file

@ -1,4 +1,3 @@
import { countdownTypes } from '../../config/generalConfig.mjs';
import { GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
import constructHTMLButton from '../../helpers/utils.mjs';
import OwnershipSelection from '../dialogs/ownershipSelection.mjs';
@ -328,43 +327,29 @@ export class EncounterCountdowns extends Countdowns {
};
}
export const registerCountdownApplicationHooks = () => {
const updateCountdowns = async shouldProgress => {
if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).countdowns) {
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
for (let countdownCategoryKey in countdownSetting) {
const countdownCategory = countdownSetting[countdownCategoryKey];
for (let countdownKey in countdownCategory.countdowns) {
const countdown = countdownCategory.countdowns[countdownKey];
if (shouldProgress(countdown)) {
await countdownSetting.updateSource({
[`${countdownCategoryKey}.countdowns.${countdownKey}.progress.current`]:
countdown.progress.current - 1
});
await game.settings.set(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Countdowns,
countdownSetting
);
foundry.applications.instances.get(`${countdownCategoryKey}-countdowns`)?.render();
}
export async function updateCountdowns(progressType) {
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
const update = Object.keys(countdownSetting).reduce((update, typeKey) => {
return foundry.utils.mergeObject(
update,
Object.keys(countdownSetting[typeKey].countdowns).reduce((acc, countdownKey) => {
const countdown = countdownSetting[typeKey].countdowns[countdownKey];
if (countdown.progress.current > 0 && countdown.progress.type.value === progressType) {
acc[`${typeKey}.countdowns.${countdownKey}.progress.current`] = countdown.progress.current - 1;
}
}
}
};
Hooks.on(CONFIG.DH.HOOKS.characterAttack, async () => {
updateCountdowns(countdown => {
return (
countdown.progress.type.value === countdownTypes.characterAttack.id && countdown.progress.current > 0
);
});
});
return acc;
}, {})
);
}, {});
Hooks.on(CONFIG.DH.HOOKS.spotlight, async () => {
updateCountdowns(countdown => {
return countdown.progress.type.value === countdownTypes.spotlight.id && countdown.progress.current > 0;
});
await countdownSetting.updateSource(update);
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, countdownSetting);
const data = { refreshType: RefreshType.Countdown };
await game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.Refresh,
data
});
};
Hooks.callAll(socketEvent.Refresh, data);
}

View file

@ -4,7 +4,6 @@ export * as domainConfig from './domainConfig.mjs';
export * as effectConfig from './effectConfig.mjs';
export * as flagsConfig from './flagsConfig.mjs';
export * as generalConfig from './generalConfig.mjs';
export * as hooksConfig from './hooksConfig.mjs';
export * as itemConfig from './itemConfig.mjs';
export * as settingsConfig from './settingsConfig.mjs';
export * as systemConfig from './system.mjs';

View file

@ -376,15 +376,15 @@ export const abilityCosts = {
export const countdownTypes = {
spotlight: {
id: 'spotlight',
label: 'DAGGERHEART.CONFIG.CountdownTypes.Spotlight'
label: 'DAGGERHEART.CONFIG.CountdownType.spotlight'
},
characterAttack: {
id: 'characterAttack',
label: 'DAGGERHEART.CONFIG.CountdownTypes.CharacterAttack'
label: 'DAGGERHEART.CONFIG.CountdownType.characterAttack'
},
custom: {
id: 'custom',
label: 'DAGGERHEART.CONFIG.CountdownTypes.Custom'
label: 'DAGGERHEART.CONFIG.CountdownType.custom'
}
};
export const rollTypes = {

View file

@ -1,4 +0,0 @@
export const hooks = {
characterAttack: 'characterAttackHook',
spotlight: 'spotlightHook'
};

View file

@ -3,7 +3,6 @@ import * as DOMAIN from './domainConfig.mjs';
import * as ACTOR from './actorConfig.mjs';
import * as ITEM from './itemConfig.mjs';
import * as SETTINGS from './settingsConfig.mjs';
import { hooks as HOOKS } from './hooksConfig.mjs';
import * as EFFECTS from './effectConfig.mjs';
import * as ACTIONS from './actionConfig.mjs';
import * as FLAGS from './flagsConfig.mjs';
@ -17,7 +16,6 @@ export const SYSTEM = {
ACTOR,
ITEM,
SETTINGS,
HOOKS,
EFFECTS,
ACTIONS,
FLAGS

View file

@ -38,6 +38,15 @@ export default class DHAttackAction extends DHDamageAction {
};
}
async use(event, ...args) {
const result = await super.use(event, args);
const { updateCountdowns } = game.system.api.applications.ui.DhCountdowns;
await updateCountdowns(CONFIG.DH.GENERAL.countdownTypes.characterAttack.id);
return result;
}
// get modifiers() {
// return [];
// }

View file

@ -102,7 +102,7 @@ class DhCountdown extends foundry.abstract.DataModel {
value: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.countdownTypes,
initial: CONFIG.DH.GENERAL.countdownTypes.spotlight.id,
initial: CONFIG.DH.GENERAL.countdownTypes.custom.id,
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.type.value.label'
}),
label: new fields.StringField({
@ -132,7 +132,13 @@ class DhCountdown extends foundry.abstract.DataModel {
export const registerCountdownHooks = () => {
Hooks.on(socketEvent.Refresh, ({ refreshType, application }) => {
if (refreshType === RefreshType.Countdown) {
foundry.applications.instances.get(application)?.render();
if (application) {
foundry.applications.instances.get(application)?.render();
} else {
foundry.applications.instances.get('narrative-countdowns').render();
foundry.applications.instances.get('encounter-countdowns').render();
}
return false;
}
});

View file

@ -4,20 +4,22 @@ export default class DhAutomation extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
hope: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hope.label'
}), // Label need to be updated into something like "Duality Roll Auto Gain" + a hint
hopeFear: new fields.SchemaField({
gm: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.gm.label'
}),
players: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.players.label'
})
}),
actionPoints: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.actionPoints.label'
}),
countdowns: new fields.BooleanField({
requireD: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.countdowns.label'
})
};
}

View file

@ -175,9 +175,10 @@ export default class DHRoll extends Roll {
export const registerRollDiceHooks = () => {
Hooks.on(`${CONFIG.DH.id}.postRollDuality`, async (config, message) => {
const hopeFearAutomation = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hopeFear;
if (
!config.source?.actor ||
!game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).hope ||
(game.user.isGM ? !hopeFearAutomation.gm : !hopeFearAutomation.players) ||
config.roll.type === 'reaction'
)
return;
@ -185,9 +186,9 @@ export const registerRollDiceHooks = () => {
const actor = await fromUuid(config.source.actor),
updates = [];
if (!actor) return;
if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ type: 'hope', value: 1 });
if (config.roll.isCritical) updates.push({ type: 'stress', value: -1 });
if (config.roll.result.duality === -1) updates.push({ type: 'fear', value: 1 });
if (config.roll.isCritical || config.roll.result.duality === 1) updates.push({ key: 'hope', value: 1 });
if (config.roll.isCritical) updates.push({ key: 'stress', value: -1 });
if (config.roll.result.duality === -1) updates.push({ key: 'fear', value: 1 });
if (updates.length) actor.modifyResource(updates);

View file

@ -1,5 +1,10 @@
<div>
{{formGroup settingFields.schema.fields.hope value=settingFields._source.hope localize=true}}
<div class="form-group">
<label>{{localize "DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.label"}}</label>
{{formGroup settingFields.schema.fields.hopeFear.fields.gm value=settingFields._source.hopeFear.gm localize=true}}
{{formGroup settingFields.schema.fields.hopeFear.fields.players value=settingFields._source.hopeFear.players localize=true}}
</div>
{{formGroup settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints localize=true}}
{{formGroup settingFields.schema.fields.countdowns value=settingFields._source.countdowns localize=true}}