diff --git a/daggerheart.mjs b/daggerheart.mjs index ae93253c..ae1502b0 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -10,7 +10,7 @@ import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module. import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } from './module/dice/_module.mjs'; import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'; -import { enrichedFateRoll, getFateTypeData } from './module/enrichers/FateRollEnricher.mjs'; +import { enrichedFateRoll, getFateType } from './module/enrichers/FateRollEnricher.mjs'; import { handlebarsRegistration, runMigrations, @@ -322,26 +322,29 @@ Hooks.on('chatMessage', (_, message) => { if (message.startsWith('/fr')) { const result = message.trim().toLowerCase() === '/fr' ? { result: {} } : rollCommandToJSON(message.replace(/\/fr\s?/, '')); - if (!result) { ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing')); return false; } const { result: rollCommand, flavor } = result; - const fateTypeData = getFateTypeData(rollCommand?.type); - if (!fateTypeData) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); + const fateTypeFromRollCommand = getFateType(rollCommand?.type); + + 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 title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll'); + const title = fateType + ' Fate Roll'; enrichedFateRoll({ target, title, - label: fateTypeLabel, + label: 'test', fateType }); return false; diff --git a/lang/en.json b/lang/en.json index 69965b9e..82129bac 100755 --- a/lang/en.json +++ b/lang/en.json @@ -237,13 +237,10 @@ "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", - "resetCharacter": "Reset Character", "viewParty": "View Party", "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?", - "cancelBeastform": "Cancel Beastform", - "resetCharacterConfirmationTitle": "Reset Character", - "resetCharacterConfirmationContent": "You are reseting all character data except name and portrait. Are you sure?" + "cancelBeastform": "Cancel Beastform" }, "Companion": { "FIELDS": { @@ -317,8 +314,6 @@ "selectPrimaryWeapon": "Select Primary Weapon", "selectSecondaryWeapon": "Select Secondary Weapon", "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", "story": "Story", "storyExplanation": "Select which background and connection prompts you want to copy into your character's background.", @@ -620,11 +615,9 @@ "rerollDice": "Reroll Dice" }, "RiskItAllDialog": { - "title": "{name} - Risk It All", - "subtitle": "Clear Stress and Hit Points", - "remainingTitle": "Remaining Points", - "clearResource": "Clear {resource}", - "finalTitle": "Final Character Resources" + "title": "Character: {name} - Risk It All - Clear Stress and/or Hit Points", + "subtitle": "Clear {hope} Stress and/or Hit Points", + "submit": "Submit" }, "TagTeamSelect": { "title": "Tag Team Roll", @@ -2468,6 +2461,10 @@ "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." }, + "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": { "label": "Roll", @@ -2678,9 +2675,9 @@ "riskItAllCritical": "Critical Rolled, clearing all marked Stress and Hit Points.", "riskItAllFailure": "The fear die rolled higher. You have crossed through the veil of death.", "blazeOfGlory": "Blaze of Glory Effect Added!", - "riskItAllDialogButton": "Clear Stress And Hit Points.", - "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 And Hit Points." + "riskItAllClearStressAndHitPoints": "Clear {hope} Stress Or Hit Points.", + "riskItAllSuccessWithEnoughHope": "Hope roll value is more than the marked Stress and Hit Points, clearing both.", + "riskItAllSuccess": "The hope die rolled higher, clear up to {hope} Stress Or Hit Points." }, "dicePool": { "title": "Dice Pool" diff --git a/module/applications/dialogs/_module.mjs b/module/applications/dialogs/_module.mjs index d43045e6..92038c41 100644 --- a/module/applications/dialogs/_module.mjs +++ b/module/applications/dialogs/_module.mjs @@ -14,4 +14,3 @@ export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs'; export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs'; export { default as GroupRollDialog } from './group-roll-dialog.mjs'; export { default as TagTeamDialog } from './tagTeamDialog.mjs'; -export { default as RiskItAllDialog } from './riskItAllDialog.mjs'; diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index 6f320152..441842dc 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -123,7 +123,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio context.formula = this.roll.constructFormula(this.config); if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers(); - context.showReaction = !this.config.skips?.reaction && context.rollType === 'DualityRoll'; + context.showReaction = !this.config.roll?.type || context.rollType === 'DualityRoll'; context.reactionOverride = this.reactionOverride; } diff --git a/module/applications/dialogs/deathMove.mjs b/module/applications/dialogs/deathMove.mjs index 18ebf104..ea7a18eb 100644 --- a/module/applications/dialogs/deathMove.mjs +++ b/module/applications/dialogs/deathMove.mjs @@ -9,7 +9,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV this.actor = actor; this.selectedMove = null; this.showRiskItAllButton = false; - this.riskItAllButtonLabel = ''; + this.riskItAllButtonLabel = ""; this.riskItAllHope = 0; } @@ -84,7 +84,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV label: game.i18n.localize('DAGGERHEART.GENERAL.dualityDice'), actionType: null, advantage: null, - customConfig: { skips: { resources: true, reaction: true } } + customConfig: { skips: { resources: true } } }); if (!config.roll.result) return; @@ -108,12 +108,10 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV config.resourceUpdates.addResources(clearAllStressAndHitpointsUpdates); chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllSuccessWithEnoughHope'); } 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.riskItAllHope = config.roll.hope.value; - this.riskItAllButtonLabel = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllDialogButton'); + this.riskItAllButtonLabel = game.i18n.format('DAGGERHEART.UI.Chat.deathMove.riskItAllClearStressAndHitPoints', { hope: config.roll.hope.value }) } } diff --git a/module/applications/dialogs/riskItAllDialog.mjs b/module/applications/dialogs/riskItAllDialog.mjs index 9bdd5dc2..fef76e66 100644 --- a/module/applications/dialogs/riskItAllDialog.mjs +++ b/module/applications/dialogs/riskItAllDialog.mjs @@ -1,14 +1,11 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; export default class RiskItAllDialog extends HandlebarsApplicationMixin(ApplicationV2) { - constructor(actor, resourceValue) { + constructor(actor, config) { super({}); this.actor = actor; - this.resourceValue = resourceValue; - this.choices = { - hitPoints: 0, - stress: 0 - }; + this.validChoices = null; + this.config = config; } get title() { @@ -17,10 +14,10 @@ export default class RiskItAllDialog extends HandlebarsApplicationMixin(Applicat static DEFAULT_OPTIONS = { classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'risk-it-all'], - position: { width: 280, height: 'auto' }, - window: { icon: 'fa-solid fa-dice fa-xl' }, + position: { width: 'auto', height: 'auto' }, + window: { icon: 'fa-solid fa-skull' }, actions: { - finish: RiskItAllDialog.#finish + submit: this.submit } }; @@ -31,62 +28,42 @@ 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) { const context = await super._prepareContext(_options); - context.resourceValue = this.resourceValue; - context.remainingResource = this.resourceValue - this.choices.hitPoints - this.choices.stress; - context.unfinished = context.remainingResource !== 0; + context.RiskItAllDialog = this.RiskItAllDialog; + context.title = game.i18n.format('DAGGERHEART.APPLICATIONS.RiskItAllDialog.subtitle', { hope: this.config.hope }); + context.currentHitPointsLabel = "Current Marked Hit Points: " + this.actor.system.resources.hitPoints.value; + context.currentStressLabel = "Current Marked Stress: " + this.actor.system.resources.stress.value; - context.choices = this.choices; - 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; + context.newHitPoints = this.actor.system.resources.hitPoints.value; + context.newStress = this.actor.system.resources.stress.value; return context; } - updateChoice(event) { - let value = Number.parseInt(event.target.value); - 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]; + static checkForValidChoice() { + /* + TODO: - /* If trying to increase beyond remaining resource points, just increase to max available */ - if (remaining - changeAmount < 0) value = this.choices[choiceKey] + remaining; - else if (actorValue - value < 0) value = actorValue; - - this.choices[choiceKey] = value; - this.render(); + return (this.config.hope == (this.actor.system.resources.hitPoints.value - newHitPointValue) + (this.actor.system.resources.stress.value - newStressValue)); + */ + return true; } - static async #finish() { - const resourceUpdate = Object.keys(this.choices).reduce((acc, resourceKey) => { - const value = this.actor.system.resources[resourceKey].value - this.choices[resourceKey]; - acc[resourceKey] = { value }; - return acc; - }, {}); - - await this.actor.update({ - 'system.resources': resourceUpdate - }); - + static async submit() { this.close(); + // TODO: Update actor with changes. + await this.actor.update({ + system: { + resources: { + hitPoints: { + value: 0 // TODO put editted value here + }, + stress: { + value: 0 // TODO put editted value here + } + } + } + }); } } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 5c6bac3a..5086757d 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -27,7 +27,6 @@ export default class CharacterSheet extends DHBaseActorSheet { makeDeathMove: CharacterSheet.#makeDeathMove, levelManagement: CharacterSheet.#levelManagement, viewLevelups: CharacterSheet.#viewLevelups, - resetCharacter: CharacterSheet.#resetCharacter, toggleEquipItem: CharacterSheet.#toggleEquipItem, toggleResourceDice: CharacterSheet.#toggleResourceDice, handleResourceDice: CharacterSheet.#handleResourceDice, @@ -43,11 +42,6 @@ export default class CharacterSheet extends DHBaseActorSheet { icon: 'fa-solid fa-angles-up', label: 'DAGGERHEART.ACTORS.Character.viewLevelups', action: 'viewLevelups' - }, - { - icon: 'fa-solid fa-arrow-rotate-left', - label: 'DAGGERHEART.ACTORS.Character.resetCharacter', - action: 'resetCharacter' } ] }, @@ -226,6 +220,13 @@ export default class CharacterSheet extends DHBaseActorSheet { async _preparePartContext(partId, context, options) { context = await super._preparePartContext(partId, context, options); 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': await this._prepareLoadoutContext(context, options); break; @@ -665,32 +666,6 @@ export default class CharacterSheet extends DHBaseActorSheet { 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. * @type {ApplicationClickAction} @@ -980,18 +955,6 @@ export default class CharacterSheet extends DHBaseActorSheet { } 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) { return super._onDropItem(event, item); } diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index f0c7288c..b4aa246a 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -1,5 +1,6 @@ import { abilities } from '../../config/actorConfig.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 { constructor(options) { @@ -97,17 +98,15 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo /** Ensure the chat theme inherits the interface theme */ _replaceHTML(result, content, options) { - const themedElement = result.log?.querySelector('.chat-log'); - themedElement?.classList.remove('themed', 'theme-light', 'theme-dark'); + const themedElement = result.log?.querySelector(".chat-log"); + themedElement?.classList.remove("themed", "theme-light", "theme-dark"); super._replaceHTML(result, content, options); } /** Remove chat log theme from notifications area */ async _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) { @@ -389,8 +388,14 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo event.target.closest('.group-roll-section').querySelector('.group-roll-content').classList.toggle('closed'); } + async riskItAllClearStressAndHitPoints(event, data) { - const resourceValue = event.target.dataset.resourceValue; - new game.system.api.applications.dialogs.RiskItAllDialog(data.actor, resourceValue).render({ force: true }); + const hopeValue = event.target.dataset.hope; + const config = { + hope: hopeValue + } + await new RiskItAllDialog(data.actor, config).render({ force: true }); } + + } diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index bff0bae9..3376b153 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -55,6 +55,11 @@ export default class DhAutomation extends foundry.abstract.DataModel { initial: true, 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({ enabled: new fields.BooleanField({ required: true, diff --git a/module/enrichers/FateRollEnricher.mjs b/module/enrichers/FateRollEnricher.mjs index c50a563b..c1b73bae 100644 --- a/module/enrichers/FateRollEnricher.mjs +++ b/module/enrichers/FateRollEnricher.mjs @@ -4,35 +4,56 @@ export default function DhFateRollEnricher(match, _options) { const roll = rollCommandToJSON(match[1], 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); } -export function getFateTypeData(fateTypeValue) { - const value = fateTypeValue ? fateTypeValue.capitalize() : 'Hope'; - const lowercased = fateTypeValue?.toLowerCase?.() ?? 'hope'; - switch (lowercased) { - case 'hope': - case 'fear': - return { value, label: game.i18n.localize(`DAGGERHEART.GENERAL.${lowercased}`) }; - default: - return null; - } +export function getFateType(fateTypeValue) { + const fateTypeFromValue = fateTypeValue + ? fateTypeValue.toLowerCase() == 'fear' + ? 'Fear' + : fateTypeValue.toLowerCase() == 'hope' + ? 'Hope' + : 'BAD' + : 'Hope'; + + return fateTypeFromValue; } function getFateMessage(roll, flavor) { - const fateTypeData = getFateTypeData(roll?.type); + const fateType = getFateType(roll?.type); - if (!fateTypeData) - return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); + if (fateType == 'BAD') { + ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); + return ''; + } - const { value: fateType, label: fateTypeLabel } = fateTypeData; - const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll'); + const fateTypeLocalized = + fateType === 'Hope' + ? 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'); fateElement.innerHTML = ` - +
+

{{title}}

+
+
+ Remaining points to use here.
+
+
+ {{currentHitPointsLabel}} +
+ New Hit Points Value + +
+ + {{currentStressLabel}} +
+ New Stress Value + +
+
+
+ \ No newline at end of file diff --git a/templates/settings/automation-settings/general.hbs b/templates/settings/automation-settings/general.hbs index bd91b2b1..d49ef9b8 100644 --- a/templates/settings/automation-settings/general.hbs +++ b/templates/settings/automation-settings/general.hbs @@ -18,6 +18,7 @@ {{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.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.resourceScrollTexts value=settingFields._source.resourceScrollTexts localize=true}} diff --git a/templates/sheets-settings/action-settings/trigger.hbs b/templates/sheets-settings/action-settings/trigger.hbs index 9ef97733..b048461e 100644 --- a/templates/sheets-settings/action-settings/trigger.hbs +++ b/templates/sheets-settings/action-settings/trigger.hbs @@ -30,7 +30,7 @@
- {{formInput @root.fields.triggers.element.fields.command value=trigger.command elementType="code-mirror" name=(concat "triggers." index ".command") }} + {{formInput @root.fields.triggers.element.fields.command value=trigger.command elementType="code-mirror" name=(concat "triggers." index ".command") aria=(object label=(localize "Test")) }}
{{/each}} diff --git a/templates/sheets/actors/character/header.hbs b/templates/sheets/actors/character/header.hbs index d2c01f3c..38c3a770 100644 --- a/templates/sheets/actors/character/header.hbs +++ b/templates/sheets/actors/character/header.hbs @@ -128,7 +128,9 @@ {{/each}} - {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' }} - + {{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' showSettings=showSettings }} + {{#if ../showSettings}} + + {{/if}} {{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}} \ No newline at end of file diff --git a/templates/ui/chat/deathMove.hbs b/templates/ui/chat/deathMove.hbs index 02691c7c..b36ee590 100644 --- a/templates/ui/chat/deathMove.hbs +++ b/templates/ui/chat/deathMove.hbs @@ -19,7 +19,7 @@ {{#if this.showRiskItAllButton}}
-