Added support for reload rules

This commit is contained in:
WBHarry 2026-07-01 12:53:48 +02:00
parent 70388dbd73
commit 3817469e35
11 changed files with 99 additions and 3 deletions

View file

@ -122,6 +122,10 @@
"damageOnSave": "Damage on Save",
"useDefaultItemValues": "Use default Item values"
},
"Reload": {
"checkReload": "Check Reload",
"reloadRequired": "Reload Required!"
},
"RollField": {
"diceRolling": {
"compare": "Should be",
@ -2786,6 +2790,10 @@
"hint": "Effects with defined range dependency will automatically turn on/off depending on range"
}
},
"reload": {
"label": "Reload Checking",
"hint": "If the system should present a button for checking if the character will need to reload or do it automatically"
},
"resourceScrollTexts": {
"label": "Show Resource Change Scrolltexts",
"hint": "When a character is damaged, uses armor etc, a scrolling text will briefly appear by the token to signify this."

View file

@ -152,6 +152,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
html.querySelectorAll('.risk-it-all-button').forEach(element =>
element.addEventListener('click', event => this.riskItAllClearStressAndHitPoints(event, data))
);
for (const element of html.querySelectorAll('.roll-reload-check')) {
element.addEventListener('click', event => this.onRollReloadCheck(event, message));
}
};
setupHooks() {
@ -297,4 +300,12 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
const actor = game.actors.get(event.target.dataset.actorId);
new game.system.api.applications.dialogs.RiskItAllDialog(actor, resourceValue).render({ force: true });
}
async onRollReloadCheck(_event, messageData) {
const message = game.messages.get(messageData._id);
const needReload = await message.system.action.handleReload?.({ awaitRoll: true });
await message.update({
'system.needReload': needReload
});
}
}

View file

@ -59,3 +59,18 @@ export const actionAutomationChoices = {
label: 'DAGGERHEART.CONFIG.ActionAutomationChoices.always'
}
};
export const reloadChoices = {
off: {
id: 'off',
label: 'Don\'t Use'
},
button: {
id: 'button',
label: 'Use Button'
},
auto: {
id: 'auto',
label: 'Automatic'
}
};

View file

@ -61,6 +61,24 @@ export default class DHAttackAction extends DHDamageAction {
return result;
}
async handleReload(options = { awaitRoll: false }) {
const roll = await new Roll('1d6').evaluate();
if (game.modules.get('dice-so-nice')?.active) {
if (options.awaitRoll)
await game.dice3d.showForRoll(roll, game.user, true);
else
game.dice3d.showForRoll(roll, game.user, true);
}
const needsToReload = roll.total === 1;
if (needsToReload) {
// TODO: Update item resource value when the functionality has been added to the system
// this.item.update({ 'system.resource.value': 0 });
}
return true;
return needsToReload;
}
/**
* Generate a localized label array for this item subtype.
* @returns {(string | { value: string, icons: string[] })[]} An array of localized strings and damage label objects.

View file

@ -41,6 +41,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
hasEffect: new fields.BooleanField({ initial: false }),
hasSave: new fields.BooleanField({ initial: false }),
hasTarget: new fields.BooleanField({ initial: false }),
needReload: new fields.BooleanField({ initial: false }),
isDirect: new fields.BooleanField({ initial: false }),
onSave: new fields.StringField(),
source: new fields.SchemaField({

View file

@ -117,6 +117,10 @@ export default class DHWeapon extends AttachableItem {
return this.weaponFeatures;
}
get hasReload() {
return Boolean(this.weaponFeatures.find(x => x.value === 'reloading'));
}
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;

View file

@ -196,6 +196,13 @@ export default class DhAutomation extends foundry.abstract.DataModel {
})
})
}),
reload: new fields.StringField({
required: true,
choices: CONFIG.DH.SETTINGS.reloadChoices,
initial: CONFIG.DH.SETTINGS.reloadChoices.button.id,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.reload.label',
hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.reload.hint'
}),
autoExpireActiveEffects: new fields.BooleanField({
required: true,
initial: true,

View file

@ -107,7 +107,11 @@ export default class DHRoll extends Roll {
static async toMessage(roll, config) {
const item = config.data.parent?.items?.get?.(config.source.item) ?? null;
const action = item ? item.system.actions.get(config.source.action) : null;
const actions = item ? [
...item.system.actions,
...(item.system.attack?.id === config.source.action ? [item.system.attack] : [])
] : [];
const action = actions.find(x => x.id === config.source.action);
let actionDescription = null;
if (action?.chatDisplay) {
actionDescription = action
@ -119,6 +123,11 @@ export default class DHRoll extends Roll {
config.actionChatMessageHandled = true;
}
const reloadSetting =
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).reload;
const useReload = item?.system.hasReload && reloadSetting === CONFIG.DH.SETTINGS.reloadChoices.auto.id;
const needReload = useReload ? await action?.handleReload?.() : false;
const cls = getDocumentClass('ChatMessage'),
msgData = {
type: this.messageType,
@ -126,7 +135,7 @@ export default class DHRoll extends Roll {
title: roll.title,
speaker: cls.getSpeaker({ actor: roll.data?.parent }),
sound: config.mute ? null : CONFIG.sounds.dice,
system: { ...config, actionDescription },
system: { ...config, actionDescription, needReload },
rolls: [roll]
};
@ -148,6 +157,7 @@ export default class DHRoll extends Roll {
if (!this._evaluated) return;
const metagamingSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming);
const automationSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options });
return foundry.applications.handlebars.renderTemplate(template, {
roll: this,
@ -155,7 +165,8 @@ export default class DHRoll extends Roll {
parent: chatData.parent,
targetMode: chatData.targetMode,
areas: chatData.action?.areas,
metagamingSettings
metagamingSettings,
automationSettings
});
}

View file

@ -271,6 +271,14 @@
}
}
.roll-reload-container {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.roll-part-extra {
display: flex;
justify-content: center;

View file

@ -18,6 +18,7 @@
<p class="hint">{{localize (concat "DAGGERHEART.SETTINGS.Automation.FIELDS.roll." field.name ".hint")}}</p>
</div>
{{/each}}
{{formGroup settingFields.schema.fields.reload value=settingFields.reload localize=true}}
</fieldset>
<fieldset>

View file

@ -1,5 +1,17 @@
<div class="chat-roll">
<div class="roll-part-title"><span>{{title}}</span></div>
{{#if (and needReload (eq automationSettings.reload 'auto'))}}
<p class="roll-reload-container">{{localize "DAGGERHEART.ACTIONS.Reload.reloadRequired"}}</p>
{{/if}}
{{#if (eq automationSettings.reload 'button')}}
<div class="roll-reload-container">
{{#if needReload}}
<p class=>{{localize "DAGGERHEART.ACTIONS.Reload.reloadRequired"}}</p>
{{/if}}
<button class="roll-reload-check" {{#if needReload}}disabled{{/if}}>{{localize "DAGGERHEART.ACTIONS.Reload.checkReload"}}</button>
</div>
{{/if}}
{{#if actionDescription}}{{> 'systems/daggerheart/templates/ui/chat/parts/description-part.hbs'}}{{/if}}
{{#if hasRoll}}
<div class="roll-part-header"><span>{{localize "Result"}}</span></div>