mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-07-21 18:09:54 +02:00
[Feature] Reload Check (#2051)
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
Some checks are pending
Project CI / build (24.x) (push) Waiting to run
This commit is contained in:
parent
8d68166e4c
commit
26bcc2dddc
22 changed files with 223 additions and 14 deletions
20
lang/en.json
20
lang/en.json
|
|
@ -126,6 +126,10 @@
|
|||
"damageOnSave": "Damage on Save",
|
||||
"useDefaultItemValues": "Use default Item values"
|
||||
},
|
||||
"Reload": {
|
||||
"checkReload": "Check Reload",
|
||||
"reloadRequired": "Reload Required!"
|
||||
},
|
||||
"RollField": {
|
||||
"diceRolling": {
|
||||
"compare": "Should be",
|
||||
|
|
@ -1322,6 +1326,11 @@
|
|||
"short": "V. Far"
|
||||
}
|
||||
},
|
||||
"ReloadChoices": {
|
||||
"off": { "label": "Don't Use" },
|
||||
"button": { "label": "Use button" },
|
||||
"auto": { "label": "Automatic" }
|
||||
},
|
||||
"RollTypes": {
|
||||
"trait": {
|
||||
"name": "Trait"
|
||||
|
|
@ -2221,7 +2230,9 @@
|
|||
},
|
||||
"Resource": {
|
||||
"single": "Resource",
|
||||
"plural": "Resources"
|
||||
"plural": "Resources",
|
||||
"unloaded": "The weapon is not loaded",
|
||||
"loaded": "The weapon is loaded"
|
||||
},
|
||||
"Roll": {
|
||||
"attack": "Attack Roll",
|
||||
|
|
@ -2797,6 +2808,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."
|
||||
|
|
@ -3258,7 +3273,8 @@
|
|||
"knowTheTide": "Know The Tide gained a token",
|
||||
"lackingItemTransferPermission": "User {user} lacks owner permission needed to transfer items to {target}",
|
||||
"noTokenTargeted": "No token is targeted",
|
||||
"behaviorRegionRequiresGM": "Creating a Region with an attached Behavior requires an online GM"
|
||||
"behaviorRegionRequiresGM": "Creating a Region with an attached Behavior requires an online GM",
|
||||
"reloadRequired": "The {weapon} must be reloaded to be used!"
|
||||
},
|
||||
"Progress": {
|
||||
"migrationLabel": "Performing system migration. Please wait and do not close Foundry."
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import DhDeathMove from '../../dialogs/deathMove.mjs';
|
|||
import { CharacterLevelup, LevelupViewMode } from '../../levelup/_module.mjs';
|
||||
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
|
||||
import FilterMenu from '../../ux/filter-menu.mjs';
|
||||
import { getArmorSources, getDocFromElement, getDocFromElementSync, sortBy } from '../../../helpers/utils.mjs';
|
||||
import { getArmorSources, getDocFromElement, getDocFromElementSync, itemAbleRollParse, sortBy } from '../../../helpers/utils.mjs';
|
||||
|
||||
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
toggleResourceDice: CharacterSheet.#toggleResourceDice,
|
||||
handleResourceDice: CharacterSheet.#handleResourceDice,
|
||||
advanceResourceDie: CharacterSheet.#advanceResourceDie,
|
||||
toggleItemReload: CharacterSheet.#onToggleItemReload,
|
||||
cancelBeastform: CharacterSheet.#cancelBeastform,
|
||||
toggleResourceManagement: CharacterSheet.#toggleResourceManagement,
|
||||
useDowntime: this.useDowntime,
|
||||
|
|
@ -954,11 +955,21 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
});
|
||||
}
|
||||
|
||||
/** */
|
||||
static #advanceResourceDie(_, target) {
|
||||
this.updateResourceDie(target, true);
|
||||
}
|
||||
|
||||
static async #onToggleItemReload(_, target) {
|
||||
const item = await getDocFromElement(target);
|
||||
if (!item || !item.system.resource?.max)
|
||||
return;
|
||||
|
||||
await item.update({
|
||||
'system.resource.value': item.system.needsReload ?
|
||||
itemAbleRollParse(item.system.resource.max, this.document, item) : 0
|
||||
})
|
||||
}
|
||||
|
||||
lowerResourceDie(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
@ -275,4 +278,10 @@ 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 needsReload = await message.system.action.handleReload?.({ awaitRoll: true });
|
||||
await message.update({ 'system.needsReload': needsReload });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,3 +62,18 @@ export const actionAutomationChoices = {
|
|||
label: 'DAGGERHEART.CONFIG.ActionAutomationChoices.always'
|
||||
}
|
||||
};
|
||||
|
||||
export const reloadChoices = {
|
||||
off: {
|
||||
id: 'off',
|
||||
label: 'DAGGERHEART.CONFIG.ReloadChoices.off.label'
|
||||
},
|
||||
button: {
|
||||
id: 'button',
|
||||
label: 'DAGGERHEART.CONFIG.ReloadChoices.button.label'
|
||||
},
|
||||
auto: {
|
||||
id: 'auto',
|
||||
label: 'DAGGERHEART.CONFIG.ReloadChoices.auto.label'
|
||||
}
|
||||
};
|
||||
|
|
@ -52,6 +52,10 @@ export default class DHAttackAction extends DHDamageAction {
|
|||
}
|
||||
|
||||
async use(event, options) {
|
||||
if (this.item?.system.needsReload) {
|
||||
return ui.notifications.error(_loc('DAGGERHEART.UI.Notifications.reloadRequired', { weapon: this.item.name }));
|
||||
}
|
||||
|
||||
const result = await super.use(event, options);
|
||||
|
||||
if (result?.message?.system.action?.roll?.type === 'attack') {
|
||||
|
|
@ -62,6 +66,23 @@ 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) {
|
||||
this.item.update({ 'system.resource.value': 0 });
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -42,6 +42,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 }),
|
||||
needsReload: new fields.BooleanField({ initial: false }),
|
||||
isDirect: new fields.BooleanField({ initial: false }),
|
||||
onSave: new fields.StringField(),
|
||||
source: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -116,6 +116,14 @@ export default class DHWeapon extends AttachableItem {
|
|||
return this.weaponFeatures;
|
||||
}
|
||||
|
||||
get hasReload() {
|
||||
return Boolean(this.weaponFeatures.find(x => x.value === 'reloading'));
|
||||
}
|
||||
|
||||
get needsReload() {
|
||||
return this.hasReload && this.resource.value === 0;
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
async getDescriptionData() {
|
||||
const baseDescription = this.description;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -117,7 +117,11 @@ export default class DHRoll extends BaseRoll {
|
|||
|
||||
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
|
||||
|
|
@ -129,6 +133,14 @@ export default class DHRoll extends BaseRoll {
|
|||
config.actionChatMessageHandled = true;
|
||||
}
|
||||
|
||||
const reloadSetting =
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).reload;
|
||||
const useReload =
|
||||
item?.system.hasReload &&
|
||||
action?.type === 'attack' &&
|
||||
reloadSetting === CONFIG.DH.SETTINGS.reloadChoices.auto.id;
|
||||
const needsReload = useReload ? await action?.handleReload?.() : false;
|
||||
|
||||
const cls = getDocumentClass('ChatMessage'),
|
||||
msgData = {
|
||||
type: this.messageType,
|
||||
|
|
@ -136,7 +148,7 @@ export default class DHRoll extends BaseRoll {
|
|||
title: roll.title,
|
||||
speaker: cls.getSpeaker({ actor: roll.data?.parent }),
|
||||
sound: config.mute ? null : CONFIG.sounds.dice,
|
||||
system: { ...config, actionDescription },
|
||||
system: { ...config, actionDescription, needsReload },
|
||||
rolls: [roll]
|
||||
};
|
||||
|
||||
|
|
@ -158,14 +170,17 @@ export default class DHRoll extends BaseRoll {
|
|||
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,
|
||||
...chatData,
|
||||
action: chatData.action,
|
||||
parent: chatData.parent,
|
||||
targetMode: chatData.targetMode,
|
||||
areas: chatData.action?.areas,
|
||||
metagamingSettings
|
||||
metagamingSettings,
|
||||
automationSettings
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@
|
|||
"source": "Daggerheart SRD",
|
||||
"page": 48,
|
||||
"artist": ""
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"recovery": null,
|
||||
"progression": "decreasing",
|
||||
"dieFaces": "d4",
|
||||
"icon": "fa-solid fa-gun"
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@
|
|||
"source": "Daggerheart SRD",
|
||||
"page": 46,
|
||||
"artist": ""
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"recovery": null,
|
||||
"progression": "decreasing",
|
||||
"dieFaces": "d4",
|
||||
"icon": "fa-solid fa-gun"
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@
|
|||
"source": "Daggerheart SRD",
|
||||
"page": 50,
|
||||
"artist": ""
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"recovery": null,
|
||||
"progression": "decreasing",
|
||||
"dieFaces": "d4",
|
||||
"icon": "fa-solid fa-gun"
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@
|
|||
"source": "Daggerheart SRD",
|
||||
"page": 49,
|
||||
"artist": ""
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"recovery": null,
|
||||
"progression": "decreasing",
|
||||
"dieFaces": "d4",
|
||||
"icon": "fa-solid fa-gun"
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
|
|
|
|||
|
|
@ -128,6 +128,15 @@
|
|||
"source": "Daggerheart SRD",
|
||||
"page": 51,
|
||||
"artist": ""
|
||||
},
|
||||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 1,
|
||||
"max": "1",
|
||||
"recovery": null,
|
||||
"progression": "decreasing",
|
||||
"dieFaces": "d4",
|
||||
"icon": "fa-solid fa-gun"
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
|
|
|
|||
|
|
@ -144,6 +144,10 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
.unloaded {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,11 @@
|
|||
height: 40px;
|
||||
flex: 1 1 calc(50% - 5px);
|
||||
|
||||
span {
|
||||
font-family: @font-body;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&:nth-last-child(1):nth-child(odd) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,9 +46,14 @@
|
|||
padding: 0 8px;
|
||||
|
||||
button {
|
||||
height: 40px;
|
||||
height: 36px;
|
||||
flex: 1 1 calc(50% - 5px);
|
||||
|
||||
span {
|
||||
font-family: @font-body;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&:nth-last-child(1):nth-child(odd) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,6 +271,28 @@
|
|||
}
|
||||
}
|
||||
|
||||
.roll-reload-container {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
|
||||
.reload-warning {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
width: fit-content;
|
||||
gap: 5px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
transition: all 0.3s ease;
|
||||
color: @beige;
|
||||
background: @red-40;
|
||||
outline: 1px solid @red;
|
||||
}
|
||||
}
|
||||
|
||||
.roll-part-extra {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -622,15 +644,19 @@
|
|||
|
||||
.roll-buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
|
||||
button {
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
height: 36px;
|
||||
flex: 1 1 calc(50% - 5px);
|
||||
font-family: @font-body;
|
||||
font-weight: 700;
|
||||
|
||||
&.end-button {
|
||||
flex: 0;
|
||||
&:nth-last-child(1):nth-child(odd) {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
{{#if (eq item.system.resource.type 'simple')}}
|
||||
<div class="item-resource">
|
||||
<i class="{{#if item.system.resource.icon}}{{item.system.resource.icon}}{{else}}fa-solid fa-hashtag{{/if}}"></i>
|
||||
<input type="number" id="{{item.uuid}}-resource" class="inventory-item-resource" value="{{item.system.resource.value}}" min="0" max="{{rollParsed item.system.resource.max item.actor item true}}" />
|
||||
{{#if item.system.hasReload}}
|
||||
<a data-action="toggleItemReload" title="{{localize (ifThen item.system.needsReload 'DAGGERHEART.GENERAL.Resource.unloaded' 'DAGGERHEART.GENERAL.Resource.loaded')}}">
|
||||
<i class="fa-solid fa-gun {{#if item.system.needsReload}}unloaded{{/if}}"></i>
|
||||
</a>
|
||||
{{else}}
|
||||
<i class="{{#if item.system.resource.icon}}{{item.system.resource.icon}}{{else}}fa-solid fa-hashtag{{/if}}"></i>
|
||||
<input type="number" id="{{item.uuid}}-resource" class="inventory-item-resource" value="{{item.system.resource.value}}" min="0" max="{{rollParsed item.system.resource.max item.actor item true}}" />
|
||||
{{/if}}
|
||||
</div>
|
||||
{{else if (eq item.system.resource.type 'diceValue')}}
|
||||
<div class="item-resources">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<div class="roll-buttons">
|
||||
{{#if (eq automationSettings.reload 'button')}}
|
||||
<button class="roll-reload-check" {{#if needsReload}}disabled{{/if}}>{{localize "DAGGERHEART.ACTIONS.Reload.checkReload"}}</button>
|
||||
{{/if}}
|
||||
{{#if areas.length}}<button class="action-areas end-button"><i class="fa-solid fa-crosshairs"></i></button>{{/if}}
|
||||
{{#if hasDamage}}
|
||||
{{#if damage.active}}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
<div class="chat-roll">
|
||||
<div class="roll-part-title"><span>{{title}}</span></div>
|
||||
|
||||
{{#if (eq action.type 'attack')}}
|
||||
{{#if needsReload}}
|
||||
<div class="roll-reload-container">
|
||||
{{#if needsReload}}
|
||||
<p class='reload-warning'>{{localize "DAGGERHEART.ACTIONS.Reload.reloadRequired"}}</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue