Compare commits

..

4 commits

Author SHA1 Message Date
WBHarry
16d839a881 . 2026-01-16 16:04:54 +01:00
WBHarry
57548b4cc4 Merge branch 'development' into feature/death-moves 2026-01-16 15:24:57 +01:00
WBHarry
8d71887924 Dialog templating and logic 2026-01-16 15:24:29 +01:00
WBHarry
98cf6fa6de
[Feature] Character Creation Confirmations (#1533)
* Added confirmation on ignoring character setup. Added reset option to character sheet.

* Removed the system setting for playerCanEdit. It's always available now.
2026-01-16 22:13:26 +10:00
17 changed files with 256 additions and 160 deletions

View file

@ -10,7 +10,7 @@ import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } from './module/dice/_module.mjs'; import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } from './module/dice/_module.mjs';
import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'; import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs';
import { enrichedFateRoll, getFateType } from './module/enrichers/FateRollEnricher.mjs'; import { enrichedFateRoll, getFateTypeData } from './module/enrichers/FateRollEnricher.mjs';
import { import {
handlebarsRegistration, handlebarsRegistration,
runMigrations, runMigrations,
@ -322,29 +322,26 @@ Hooks.on('chatMessage', (_, message) => {
if (message.startsWith('/fr')) { if (message.startsWith('/fr')) {
const result = const result =
message.trim().toLowerCase() === '/fr' ? { result: {} } : rollCommandToJSON(message.replace(/\/fr\s?/, '')); message.trim().toLowerCase() === '/fr' ? { result: {} } : rollCommandToJSON(message.replace(/\/fr\s?/, ''));
if (!result) { if (!result) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing'));
return false; return false;
} }
const { result: rollCommand, flavor } = result; const { result: rollCommand, flavor } = result;
const fateTypeData = getFateTypeData(rollCommand?.type);
const fateTypeFromRollCommand = getFateType(rollCommand?.type); if (!fateTypeData)
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
if (fateTypeFromRollCommand == 'BAD') {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return false;
}
const fateType = fateTypeFromRollCommand;
const { value: fateType, label: fateTypeLabel } = fateTypeData;
const target = getCommandTarget({ allowNull: true }); const target = getCommandTarget({ allowNull: true });
const title = fateType + ' Fate Roll'; const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll');
enrichedFateRoll({ enrichedFateRoll({
target, target,
title, title,
label: 'test', label: fateTypeLabel,
fateType fateType
}); });
return false; return false;

View file

@ -237,10 +237,13 @@
"confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)" "confirmText": "Would you like to level up your companion {name} by {levelChange} levels at this time? (You can do it manually later)"
}, },
"viewLevelups": "View Levelups", "viewLevelups": "View Levelups",
"resetCharacter": "Reset Character",
"viewParty": "View Party", "viewParty": "View Party",
"InvalidOldCharacterImportTitle": "Old Character Import", "InvalidOldCharacterImportTitle": "Old Character Import",
"InvalidOldCharacterImportText": "Character data exported prior to system version 1.1 will not generate a complete character. Do you wish to continue?", "InvalidOldCharacterImportText": "Character data exported prior to system version 1.1 will not generate a complete character. Do you wish to continue?",
"cancelBeastform": "Cancel Beastform" "cancelBeastform": "Cancel Beastform",
"resetCharacterConfirmationTitle": "Reset Character",
"resetCharacterConfirmationContent": "You are reseting all character data except name and portrait. Are you sure?"
}, },
"Companion": { "Companion": {
"FIELDS": { "FIELDS": {
@ -314,6 +317,8 @@
"selectPrimaryWeapon": "Select Primary Weapon", "selectPrimaryWeapon": "Select Primary Weapon",
"selectSecondaryWeapon": "Select Secondary Weapon", "selectSecondaryWeapon": "Select Secondary Weapon",
"selectSubclass": "Select Subclass", "selectSubclass": "Select Subclass",
"setupSkipTitle": "Skipping Character Setup",
"setupSkipContent": "You are skipping the Character Setup by adding this manually. The character setup is the blinking arrows in the top-right. Are you sure you want to continue?",
"startingItems": "Starting Items", "startingItems": "Starting Items",
"story": "Story", "story": "Story",
"storyExplanation": "Select which background and connection prompts you want to copy into your character's background.", "storyExplanation": "Select which background and connection prompts you want to copy into your character's background.",
@ -615,9 +620,11 @@
"rerollDice": "Reroll Dice" "rerollDice": "Reroll Dice"
}, },
"RiskItAllDialog": { "RiskItAllDialog": {
"title": "Character: {name} - Risk It All - Clear Stress and/or Hit Points", "title": "{name} - Risk It All",
"subtitle": "Clear {hope} Stress and/or Hit Points", "subtitle": "Clear Stress and Hit Points",
"submit": "Submit" "remainingTitle": "Remaining Points",
"clearResource": "Clear {resource}",
"finalTitle": "Final Character Resources"
}, },
"TagTeamSelect": { "TagTeamSelect": {
"title": "Tag Team Roll", "title": "Tag Team Roll",
@ -2461,10 +2468,6 @@
"label": "Show Resource Change Scrolltexts", "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." "hint": "When a character is damaged, uses armor etc, a scrolling text will briefly appear by the token to signify this."
}, },
"playerCanEditSheet": {
"label": "Players Can Manually Edit Character Settings",
"hint": "Players are allowed to access the manual Character Settings and change their statistics beyond the rules."
},
"roll": { "roll": {
"roll": { "roll": {
"label": "Roll", "label": "Roll",
@ -2675,9 +2678,9 @@
"riskItAllCritical": "Critical Rolled, clearing all marked Stress and Hit Points.", "riskItAllCritical": "Critical Rolled, clearing all marked Stress and Hit Points.",
"riskItAllFailure": "The fear die rolled higher. You have crossed through the veil of death.", "riskItAllFailure": "The fear die rolled higher. You have crossed through the veil of death.",
"blazeOfGlory": "Blaze of Glory Effect Added!", "blazeOfGlory": "Blaze of Glory Effect Added!",
"riskItAllClearStressAndHitPoints": "Clear {hope} Stress Or Hit Points.", "riskItAllDialogButton": "Clear Stress And Hit Points.",
"riskItAllSuccessWithEnoughHope": "Hope roll value is more than the marked Stress and Hit Points, clearing both.", "riskItAllSuccessWithEnoughHope": "The Hope value is more than the marked Stress and Hit Points. Both are cleared fully.",
"riskItAllSuccess": "The hope die rolled higher, clear up to {hope} Stress Or Hit Points." "riskItAllSuccess": "The hope die rolled higher, clear up to {hope} Stress And Hit Points."
}, },
"dicePool": { "dicePool": {
"title": "Dice Pool" "title": "Dice Pool"

View file

@ -14,3 +14,4 @@ export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs'; export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
export { default as GroupRollDialog } from './group-roll-dialog.mjs'; export { default as GroupRollDialog } from './group-roll-dialog.mjs';
export { default as TagTeamDialog } from './tagTeamDialog.mjs'; export { default as TagTeamDialog } from './tagTeamDialog.mjs';
export { default as RiskItAllDialog } from './riskItAllDialog.mjs';

View file

@ -123,7 +123,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
context.formula = this.roll.constructFormula(this.config); context.formula = this.roll.constructFormula(this.config);
if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers(); if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers();
context.showReaction = !this.config.roll?.type || context.rollType === 'DualityRoll'; context.showReaction = !this.config.skips?.reaction && context.rollType === 'DualityRoll';
context.reactionOverride = this.reactionOverride; context.reactionOverride = this.reactionOverride;
} }

View file

@ -9,7 +9,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
this.actor = actor; this.actor = actor;
this.selectedMove = null; this.selectedMove = null;
this.showRiskItAllButton = false; this.showRiskItAllButton = false;
this.riskItAllButtonLabel = ""; this.riskItAllButtonLabel = '';
this.riskItAllHope = 0; this.riskItAllHope = 0;
} }
@ -84,7 +84,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityDice'), label: game.i18n.localize('DAGGERHEART.GENERAL.dualityDice'),
actionType: null, actionType: null,
advantage: null, advantage: null,
customConfig: { skips: { resources: true } } customConfig: { skips: { resources: true, reaction: true } }
}); });
if (!config.roll.result) return; if (!config.roll.result) return;
@ -108,10 +108,12 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
config.resourceUpdates.addResources(clearAllStressAndHitpointsUpdates); config.resourceUpdates.addResources(clearAllStressAndHitpointsUpdates);
chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllSuccessWithEnoughHope'); chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllSuccessWithEnoughHope');
} else { } else {
chatMessage = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllSuccess', { hope: config.roll.hope.value }) chatMessage = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllSuccess', {
hope: config.roll.hope.value
});
this.showRiskItAllButton = true; this.showRiskItAllButton = true;
this.riskItAllHope = config.roll.hope.value; this.riskItAllHope = config.roll.hope.value;
this.riskItAllButtonLabel = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllClearStressAndHitPoints', { hope: config.roll.hope.value }) this.riskItAllButtonLabel = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllDialogButton');
} }
} }

View file

@ -1,11 +1,14 @@
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class RiskItAllDialog extends HandlebarsApplicationMixin(ApplicationV2) { export default class RiskItAllDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor, config) { constructor(actor, resourceValue) {
super({}); super({});
this.actor = actor; this.actor = actor;
this.validChoices = null; this.resourceValue = resourceValue;
this.config = config; this.choices = {
hitPoints: 0,
stress: 0
};
} }
get title() { get title() {
@ -14,10 +17,10 @@ export default class RiskItAllDialog extends HandlebarsApplicationMixin(Applicat
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'risk-it-all'], classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'risk-it-all'],
position: { width: 'auto', height: 'auto' }, position: { width: 280, height: 'auto' },
window: { icon: 'fa-solid fa-skull' }, window: { icon: 'fa-solid fa-dice fa-xl' },
actions: { actions: {
submit: this.submit finish: RiskItAllDialog.#finish
} }
}; };
@ -28,42 +31,62 @@ export default class RiskItAllDialog extends HandlebarsApplicationMixin(Applicat
} }
}; };
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
for (const input of htmlElement.querySelectorAll('.resource-container input'))
input.addEventListener('change', this.updateChoice.bind(this));
}
async _prepareContext(_options) { async _prepareContext(_options) {
const context = await super._prepareContext(_options); const context = await super._prepareContext(_options);
context.RiskItAllDialog = this.RiskItAllDialog; context.resourceValue = this.resourceValue;
context.title = game.i18n.format('DAGGERHEART.APPLICATIONS.RiskItAllDialog.subtitle', { hope: this.config.hope }); context.remainingResource = this.resourceValue - this.choices.hitPoints - this.choices.stress;
context.currentHitPointsLabel = "Current Marked Hit Points: " + this.actor.system.resources.hitPoints.value; context.unfinished = context.remainingResource !== 0;
context.currentStressLabel = "Current Marked Stress: " + this.actor.system.resources.stress.value;
context.newHitPoints = this.actor.system.resources.hitPoints.value; context.choices = this.choices;
context.newStress = this.actor.system.resources.stress.value; context.final = {
hitPoints: {
value: this.actor.system.resources.hitPoints.value - this.choices.hitPoints,
max: this.actor.system.resources.hitPoints.max
},
stress: {
value: this.actor.system.resources.stress.value - this.choices.stress,
max: this.actor.system.resources.stress.max
}
};
context;
return context; return context;
} }
static checkForValidChoice() { updateChoice(event) {
/* let value = Number.parseInt(event.target.value);
TODO: const choiceKey = event.target.dataset.choice;
const actorValue = this.actor.system.resources[choiceKey].value;
const remaining = this.resourceValue - this.choices.hitPoints - this.choices.stress;
const changeAmount = value - this.choices[choiceKey];
return (this.config.hope == (this.actor.system.resources.hitPoints.value - newHitPointValue) + (this.actor.system.resources.stress.value - newStressValue)); /* If trying to increase beyond remaining resource points, just increase to max available */
*/ if (remaining - changeAmount < 0) value = this.choices[choiceKey] + remaining;
return true; else if (actorValue - value < 0) value = actorValue;
this.choices[choiceKey] = value;
this.render();
} }
static async submit() { static async #finish() {
this.close(); const resourceUpdate = Object.keys(this.choices).reduce((acc, resourceKey) => {
// TODO: Update actor with changes. const value = this.actor.system.resources[resourceKey].value - this.choices[resourceKey];
acc[resourceKey] = { value };
return acc;
}, {});
await this.actor.update({ await this.actor.update({
system: { 'system.resources': resourceUpdate
resources: {
hitPoints: {
value: 0 // TODO put editted value here
},
stress: {
value: 0 // TODO put editted value here
}
}
}
}); });
this.close();
} }
} }

View file

@ -27,6 +27,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
makeDeathMove: CharacterSheet.#makeDeathMove, makeDeathMove: CharacterSheet.#makeDeathMove,
levelManagement: CharacterSheet.#levelManagement, levelManagement: CharacterSheet.#levelManagement,
viewLevelups: CharacterSheet.#viewLevelups, viewLevelups: CharacterSheet.#viewLevelups,
resetCharacter: CharacterSheet.#resetCharacter,
toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleEquipItem: CharacterSheet.#toggleEquipItem,
toggleResourceDice: CharacterSheet.#toggleResourceDice, toggleResourceDice: CharacterSheet.#toggleResourceDice,
handleResourceDice: CharacterSheet.#handleResourceDice, handleResourceDice: CharacterSheet.#handleResourceDice,
@ -42,6 +43,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
icon: 'fa-solid fa-angles-up', icon: 'fa-solid fa-angles-up',
label: 'DAGGERHEART.ACTORS.Character.viewLevelups', label: 'DAGGERHEART.ACTORS.Character.viewLevelups',
action: 'viewLevelups' action: 'viewLevelups'
},
{
icon: 'fa-solid fa-arrow-rotate-left',
label: 'DAGGERHEART.ACTORS.Character.resetCharacter',
action: 'resetCharacter'
} }
] ]
}, },
@ -220,13 +226,6 @@ export default class CharacterSheet extends DHBaseActorSheet {
async _preparePartContext(partId, context, options) { async _preparePartContext(partId, context, options) {
context = await super._preparePartContext(partId, context, options); context = await super._preparePartContext(partId, context, options);
switch (partId) { switch (partId) {
case 'header':
const { playerCanEditSheet, levelupAuto } = game.settings.get(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Automation
);
context.showSettings = game.user.isGM || !levelupAuto || (levelupAuto && playerCanEditSheet);
break;
case 'loadout': case 'loadout':
await this._prepareLoadoutContext(context, options); await this._prepareLoadoutContext(context, options);
break; break;
@ -666,6 +665,32 @@ export default class CharacterSheet extends DHBaseActorSheet {
new LevelupViewMode(this.document).render({ force: true }); new LevelupViewMode(this.document).render({ force: true });
} }
/**
* Resets the character data and removes all embedded documents.
*/
static async #resetCharacter() {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.resetCharacterConfirmationTitle')
},
content: game.i18n.localize('DAGGERHEART.ACTORS.Character.resetCharacterConfirmationContent')
});
if (!confirmed) return;
await this.document.update({
'==system': {}
});
await this.document.deleteEmbeddedDocuments(
'Item',
this.document.items.map(x => x.id)
);
await this.document.deleteEmbeddedDocuments(
'ActiveEffect',
this.document.effects.map(x => x.id)
);
}
/** /**
* Opens the Death Move interface for the character. * Opens the Death Move interface for the character.
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
@ -955,6 +980,18 @@ export default class CharacterSheet extends DHBaseActorSheet {
} }
async _onDropItem(event, item) { async _onDropItem(event, item) {
const setupCriticalItemTypes = ['class', 'subclass', 'ancestry', 'community'];
if (this.document.system.needsCharacterSetup && setupCriticalItemTypes.includes(item.type)) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.CharacterCreation.setupSkipTitle')
},
content: game.i18n.localize('DAGGERHEART.APPLICATIONS.CharacterCreation.setupSkipContent')
});
if (!confirmed) return;
}
if (this.document.uuid === item.parent?.uuid) { if (this.document.uuid === item.parent?.uuid) {
return super._onDropItem(event, item); return super._onDropItem(event, item);
} }

View file

@ -1,6 +1,5 @@
import { abilities } from '../../config/actorConfig.mjs'; import { abilities } from '../../config/actorConfig.mjs';
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs'; import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
import RiskItAllDialog from '../dialogs/riskItAllDialog.mjs';
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog { export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
constructor(options) { constructor(options) {
@ -98,15 +97,17 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
/** Ensure the chat theme inherits the interface theme */ /** Ensure the chat theme inherits the interface theme */
_replaceHTML(result, content, options) { _replaceHTML(result, content, options) {
const themedElement = result.log?.querySelector(".chat-log"); const themedElement = result.log?.querySelector('.chat-log');
themedElement?.classList.remove("themed", "theme-light", "theme-dark"); themedElement?.classList.remove('themed', 'theme-light', 'theme-dark');
super._replaceHTML(result, content, options); super._replaceHTML(result, content, options);
} }
/** Remove chat log theme from notifications area */ /** Remove chat log theme from notifications area */
async _onFirstRender(result, content) { async _onFirstRender(result, content) {
await super._onFirstRender(result, content); await super._onFirstRender(result, content);
document.querySelector("#chat-notifications .chat-log")?.classList.remove("themed", "theme-light", "theme-dark") document
.querySelector('#chat-notifications .chat-log')
?.classList.remove('themed', 'theme-light', 'theme-dark');
} }
async onRollSimple(event, message) { async onRollSimple(event, message) {
@ -388,14 +389,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
event.target.closest('.group-roll-section').querySelector('.group-roll-content').classList.toggle('closed'); event.target.closest('.group-roll-section').querySelector('.group-roll-content').classList.toggle('closed');
} }
async riskItAllClearStressAndHitPoints(event, data) { async riskItAllClearStressAndHitPoints(event, data) {
const hopeValue = event.target.dataset.hope; const resourceValue = event.target.dataset.resourceValue;
const config = { new game.system.api.applications.dialogs.RiskItAllDialog(data.actor, resourceValue).render({ force: true });
hope: hopeValue
}
await new RiskItAllDialog(data.actor, config).render({ force: true });
} }
} }

View file

@ -55,11 +55,6 @@ export default class DhAutomation extends foundry.abstract.DataModel {
initial: true, initial: true,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.resourceScrollTexts.label' label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.resourceScrollTexts.label'
}), }),
playerCanEditSheet: new fields.BooleanField({
required: true,
initial: false,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.playerCanEditSheet.label'
}),
defeated: new fields.SchemaField({ defeated: new fields.SchemaField({
enabled: new fields.BooleanField({ enabled: new fields.BooleanField({
required: true, required: true,

View file

@ -4,56 +4,35 @@ export default function DhFateRollEnricher(match, _options) {
const roll = rollCommandToJSON(match[1], match[0]); const roll = rollCommandToJSON(match[1], match[0]);
if (!roll) return match[0]; if (!roll) return match[0];
const fateTypeFromRoll = getFateType(roll?.type);
if (fateTypeFromRoll == 'BAD') {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return;
}
return getFateMessage(roll.result, roll?.flavor); return getFateMessage(roll.result, roll?.flavor);
} }
export function getFateType(fateTypeValue) { export function getFateTypeData(fateTypeValue) {
const fateTypeFromValue = fateTypeValue const value = fateTypeValue ? fateTypeValue.capitalize() : 'Hope';
? fateTypeValue.toLowerCase() == 'fear' const lowercased = fateTypeValue?.toLowerCase?.() ?? 'hope';
? 'Fear' switch (lowercased) {
: fateTypeValue.toLowerCase() == 'hope' case 'hope':
? 'Hope' case 'fear':
: 'BAD' return { value, label: game.i18n.localize(`DAGGERHEART.GENERAL.${lowercased}`) };
: 'Hope'; default:
return null;
return fateTypeFromValue; }
} }
function getFateMessage(roll, flavor) { function getFateMessage(roll, flavor) {
const fateType = getFateType(roll?.type); const fateTypeData = getFateTypeData(roll?.type);
if (fateType == 'BAD') { if (!fateTypeData)
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return '';
}
const fateTypeLocalized = const { value: fateType, label: fateTypeLabel } = fateTypeData;
fateType === 'Hope' const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll');
? game.i18n.localize('DAGGERHEART.GENERAL.hope')
: game.i18n.localize('DAGGERHEART.GENERAL.fear');
const title =
flavor ??
fateTypeLocalized +
' ' +
game.i18n.localize('DAGGERHEART.GENERAL.fate') +
' ' +
game.i18n.localize('DAGGERHEART.GENERAL.roll');
const dataLabel = game.i18n.localize('DAGGERHEART.GENERAL.fate');
const fateElement = document.createElement('span'); const fateElement = document.createElement('span');
fateElement.innerHTML = ` fateElement.innerHTML = `
<button type="button" class="fate-roll-button${roll?.inline ? ' inline' : ''}" <button type="button" class="fate-roll-button${roll?.inline ? ' inline' : ''}"
data-title="${title}" data-title="${title}"
data-label="${dataLabel}" data-label="${fateTypeLabel}"
data-fateType="${fateType}" data-fateType="${fateType}"
> >
${title} ${title}
@ -68,19 +47,17 @@ export const renderFateButton = async event => {
target = getCommandTarget({ allowNull: true }); target = getCommandTarget({ allowNull: true });
console.log('button', button); console.log('button', button);
const fateTypeFromButton = getFateType(button.dataset?.fatetype); const fateTypeData = getFateTypeData(button.dataset?.fatetype);
if (fateTypeFromButton == 'BAD') { if (!fateTypeData) ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); const { value: fateType, label: fateTypeLabel } = fateTypeData;
return;
}
await enrichedFateRoll( await enrichedFateRoll(
{ {
target, target,
title: button.dataset.title, title: button.dataset.title,
label: button.dataset.label, label: button.dataset.label,
fateType: fateTypeFromButton fateType: fateType
}, },
event event
); );
@ -93,7 +70,8 @@ export const enrichedFateRoll = async ({ target, title, label, fateType }, event
headerTitle: label, headerTitle: label,
roll: {}, roll: {},
hasRoll: true, hasRoll: true,
fateType: fateType fateType: fateType,
skips: { reaction: true }
}; };
config.data = { experiences: {}, traits: {}, fateType: fateType }; config.data = { experiences: {}, traits: {}, fateType: fateType };

View file

@ -38,4 +38,6 @@
@import './item-transfer/sheet.less'; @import './item-transfer/sheet.less';
@import './settings/change-currency-icon.less'; @import './settings/change-currency-icon.less';
@import './risk-it-all/sheet.less';

View file

@ -0,0 +1,60 @@
.daggerheart.dialog.dh-style.views.risk-it-all {
.risk-it-all-container {
display: flex;
align-items: center;
flex-direction: column;
gap: 8px;
text-align: center;
header {
font-weight: bold;
font-size: var(--font-size-20);
}
.section-label {
font-size: var(--font-size-18);
text-decoration: underline;
}
.remaining-section {
display: flex;
flex-direction: column;
gap: 2px;
}
.resource-section {
width: 100%;
display: flex;
gap: 8px;
}
.final-section {
width: 100%;
display: flex;
flex-direction: column;
gap: 2px;
.final-section-values-container {
width: 100%;
display: flex;
align-items: center;
justify-content: space-evenly;
.final-section-value-container {
display: flex;
flex-direction: column;
gap: 2px;
}
}
}
}
footer {
width: 100%;
display: flex;
button {
flex: 1;
}
}
}

View file

@ -1,33 +1,39 @@
<div> <div>
<header class="dialog-header">
<h1>{{title}}</h1>
</header>
<div>
<span>Remaining points to use here.</span>
</div>
<div class="risk-it-all-container"> <div class="risk-it-all-container">
<div class="two-columns even"> <header>{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.subtitle"}}</header>
<span>{{currentHitPointsLabel}}</span>
<div>
<span>New Hit Points Value</span>
<input type="text" data-dtype="Number" name="newHitPoints" value="{{newHitPoints}}" />
</div>
<span>{{currentStressLabel}}</span> <div class="remaining-section">
<div> <label class="section-label">{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.remainingTitle"}}</label>
<span>New Stress Value</span> <div>{{this.remainingResource}}</div>
<input type="text" data-dtype="Number" name="newStress" value="{{newStress}}" /> </div>
<div class="resource-section">
<div class="resource-container">
<label>{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.clearResource" resource=(localize "DAGGERHEART.GENERAL.HitPoints.short")}}: {{this.choices.hitPoints}}</label>
<input type="range" step="1" min="0" max="{{this.resourceValue}}" value="{{this.choices.hitPoints}}" name="choices.hitPoints" data-choice="hitPoints" />
</div>
<div class="resource-container">
<label>{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.clearResource" resource=(localize "DAGGERHEART.GENERAL.stress")}}: {{this.choices.stress}}</label>
<input type="range" step="1" min="0" max="{{this.resourceValue}}" value="{{this.choices.stress}}" name="choices.stress" data-choice="stress" />
</div> </div>
</div> </div>
<div class="final-section">
<label class="section-label">{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.finalTitle"}}</label>
<div class="final-section-values-container">
<div class="final-section-value-container">
<label>{{localize "DAGGERHEART.GENERAL.HitPoints.plural"}}</label>
<span>{{this.final.hitPoints.value}}/{{this.final.hitPoints.max}}</span>
</div>
<div class="final-section-value-container">
<label>{{localize "DAGGERHEART.GENERAL.stress"}}</label>
<span>{{this.final.stress.value}}/{{this.final.stress.max}}</span>
</div>
</div>
</div>
<footer>
<button type="button" data-action="finish" {{disabled this.unfinished}}>{{localize "Submit"}}</button>
</footer>
</div> </div>
<footer class="flexrow">
<button data-action="close">
<span>{{localize "Cancel"}}</span>
</button>
<button data-action="submit" {{#if (not this.validChoices)}}disabled{{/if}}>
<span>
{{localize "DAGGERHEART.APPLICATIONS.RiskItAllDialog.submit"}}
</span>
</button>
</footer>
</div> </div>

View file

@ -18,7 +18,6 @@
{{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}} {{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}}
{{formGroup settingFields.schema.fields.effects.fields.rangeDependent value=settingFields._source.effects.rangeDependent localize=true}} {{formGroup settingFields.schema.fields.effects.fields.rangeDependent value=settingFields._source.effects.rangeDependent localize=true}}
{{formGroup settingFields.schema.fields.levelupAuto value=settingFields._source.levelupAuto localize=true}} {{formGroup settingFields.schema.fields.levelupAuto value=settingFields._source.levelupAuto localize=true}}
{{formGroup settingFields.schema.fields.playerCanEditSheet value=settingFields._source.playerCanEditSheet localize=true}}
{{formGroup settingFields.schema.fields.damageReductionRulesDefault value=settingFields._source.damageReductionRulesDefault localize=true}} {{formGroup settingFields.schema.fields.damageReductionRulesDefault value=settingFields._source.damageReductionRulesDefault localize=true}}
{{formGroup settingFields.schema.fields.resourceScrollTexts value=settingFields._source.resourceScrollTexts localize=true}} {{formGroup settingFields.schema.fields.resourceScrollTexts value=settingFields._source.resourceScrollTexts localize=true}}
</section> </section>

View file

@ -30,7 +30,7 @@
</div> </div>
<div class="code-mirror-wrapper {{#if trigger.revealed}}revealed{{/if}}"> <div class="code-mirror-wrapper {{#if trigger.revealed}}revealed{{/if}}">
{{formInput @root.fields.triggers.element.fields.command value=trigger.command elementType="code-mirror" name=(concat "triggers." index ".command") aria=(object label=(localize "Test")) }} {{formInput @root.fields.triggers.element.fields.command value=trigger.command elementType="code-mirror" name=(concat "triggers." index ".command") }}
</div> </div>
</fieldset> </fieldset>
{{/each}} {{/each}}

View file

@ -128,9 +128,7 @@
{{/each}} {{/each}}
</div> </div>
{{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' showSettings=showSettings }} {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }}
{{#if ../showSettings}} <button type="button" data-action="openSettings" data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.openSheetSettings"}}"><i class="fa-solid fa-wrench"></i></button>
<button type="button" data-action="openSettings" data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.openSheetSettings"}}"><i class="fa-solid fa-wrench"></i></button>
{{/if}}
{{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} {{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
</header> </header>

View file

@ -19,7 +19,7 @@
</div> </div>
{{#if this.showRiskItAllButton}} {{#if this.showRiskItAllButton}}
<div> <div>
<button class="risk-it-all-button" data-hope="{{this.riskItAllHope}}"> <button class="risk-it-all-button" data-resource-value="{{this.riskItAllHope}}">
<span> <span>
{{this.riskItAllButtonLabel}} {{this.riskItAllButtonLabel}}
</span> </span>