mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 06:26:13 +01:00
Merge branch 'development' into feature-rollTableSheet
This commit is contained in:
commit
d5621d20ec
20 changed files with 345 additions and 60 deletions
|
|
@ -307,6 +307,7 @@ Hooks.on('chatMessage', (_, message) => {
|
|||
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
|
||||
: undefined;
|
||||
const difficulty = rollCommand.difficulty;
|
||||
const grantResources = Boolean(rollCommand.grantResources);
|
||||
|
||||
const target = getCommandTarget({ allowNull: true });
|
||||
const title =
|
||||
|
|
@ -324,7 +325,8 @@ Hooks.on('chatMessage', (_, message) => {
|
|||
title,
|
||||
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'),
|
||||
actionType: null,
|
||||
advantage
|
||||
advantage,
|
||||
grantResources
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
20
lang/en.json
20
lang/en.json
|
|
@ -330,6 +330,12 @@
|
|||
"title": "{actor} - Character Setup",
|
||||
"traitIncreases": "Trait Increases"
|
||||
},
|
||||
"CharacterReset": {
|
||||
"title": "Reset Character",
|
||||
"alwaysDeleteSection": "Deleted Data",
|
||||
"optionalDeleteSection": "Optional Data",
|
||||
"headerTitle": "Select which data you'd like to keep"
|
||||
},
|
||||
"CombatTracker": {
|
||||
"combatStarted": "Active",
|
||||
"giveSpotlight": "Give The Spotlight",
|
||||
|
|
@ -974,6 +980,10 @@
|
|||
"outsideRange": "Outside Range"
|
||||
},
|
||||
"Condition": {
|
||||
"deathMove": {
|
||||
"name": "Death Move",
|
||||
"description": "The character is about to make a Death Move"
|
||||
},
|
||||
"dead": {
|
||||
"name": "Dead",
|
||||
"description": "The character is dead"
|
||||
|
|
@ -2211,6 +2221,7 @@
|
|||
"single": "Player",
|
||||
"plurial": "Players"
|
||||
},
|
||||
"portrait": "Portrait",
|
||||
"proficiency": "Proficiency",
|
||||
"quantity": "Quantity",
|
||||
"range": "Range",
|
||||
|
|
@ -2442,7 +2453,11 @@
|
|||
"overlay": { "label": "Overlay Effect" },
|
||||
"characterDefault": { "label": "Character Default Defeated Status" },
|
||||
"adversaryDefault": { "label": "Adversary Default Defeated Status" },
|
||||
"companionDefault": { "label": "Companion Default Defeated Status" }
|
||||
"companionDefault": { "label": "Companion Default Defeated Status" },
|
||||
"deathMove": { "label": "Death Move" },
|
||||
"dead": { "label": "Dead" },
|
||||
"defeated": { "label": "Defeated" },
|
||||
"unconscious": { "label": "Unconscious" }
|
||||
},
|
||||
"hopeFear": {
|
||||
"label": "Hope & Fear",
|
||||
|
|
@ -2876,7 +2891,8 @@
|
|||
"documentIsMissing": "The {documentType} is missing from the world.",
|
||||
"tokenActorMissing": "{name} is missing an Actor",
|
||||
"tokenActorsMissing": "[{names}] missing Actors",
|
||||
"domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used"
|
||||
"domainTouchRequirement": "This domain card requires {nr} {domain} cards in the loadout to be used",
|
||||
"knowTheTide": "Know The Tide gained a token"
|
||||
},
|
||||
"Sidebar": {
|
||||
"actorDirectory": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export { default as AttributionDialog } from './attributionDialog.mjs';
|
||||
export { default as BeastformDialog } from './beastformDialog.mjs';
|
||||
export { default as CharacterResetDialog } from './characterResetDialog.mjs';
|
||||
export { default as d20RollDialog } from './d20RollDialog.mjs';
|
||||
export { default as DamageDialog } from './damageDialog.mjs';
|
||||
export { default as DamageReductionDialog } from './damageReductionDialog.mjs';
|
||||
|
|
|
|||
105
module/applications/dialogs/characterResetDialog.mjs
Normal file
105
module/applications/dialogs/characterResetDialog.mjs
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
export default class CharacterResetDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(actor, options = {}) {
|
||||
super(options);
|
||||
|
||||
this.actor = actor;
|
||||
this.data = {
|
||||
delete: {
|
||||
class: { keep: false, label: 'TYPES.Item.class' },
|
||||
subclass: { keep: false, label: 'TYPES.Item.subclass' },
|
||||
ancestry: { keep: false, label: 'TYPES.Item.ancestry' },
|
||||
community: { keep: false, label: 'TYPES.Item.community' }
|
||||
},
|
||||
optional: {
|
||||
portrait: { keep: true, label: 'DAGGERHEART.GENERAL.portrait' },
|
||||
name: { keep: true, label: 'Name' },
|
||||
biography: { keep: true, label: 'DAGGERHEART.GENERAL.Tabs.biography' },
|
||||
inventory: { keep: true, label: 'DAGGERHEART.GENERAL.inventory' }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'character-reset'],
|
||||
window: {
|
||||
icon: 'fa-solid fa-arrow-rotate-left',
|
||||
title: 'DAGGERHEART.APPLICATIONS.CharacterReset.title'
|
||||
},
|
||||
actions: {
|
||||
finishSelection: this.#finishSelection
|
||||
},
|
||||
form: {
|
||||
handler: this.updateData,
|
||||
submitOnChange: true,
|
||||
submitOnClose: false
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
resourceDice: {
|
||||
id: 'resourceDice',
|
||||
template: 'systems/daggerheart/templates/dialogs/characterReset.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.data = this.data;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateData(event, _, formData) {
|
||||
const { data } = foundry.utils.expandObject(formData.object);
|
||||
|
||||
this.data = foundry.utils.mergeObject(this.data, data);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static getUpdateData() {
|
||||
const update = {};
|
||||
if (!this.data.optional.portrait) update.if(!this.data.optional.biography);
|
||||
|
||||
if (!this.data.optional.inventory) return update;
|
||||
}
|
||||
|
||||
static async #finishSelection() {
|
||||
const update = {};
|
||||
if (!this.data.optional.name.keep) {
|
||||
const defaultName = game.system.api.documents.DhpActor.defaultName({ type: 'character' });
|
||||
foundry.utils.setProperty(update, 'name', defaultName);
|
||||
foundry.utils.setProperty(update, 'prototypeToken.name', defaultName);
|
||||
}
|
||||
|
||||
if (!this.data.optional.portrait.keep) {
|
||||
foundry.utils.setProperty(update, 'img', this.actor.schema.fields.img.initial(this.actor));
|
||||
foundry.utils.setProperty(update, 'prototypeToken.==texture', {});
|
||||
foundry.utils.setProperty(update, 'prototypeToken.==ring', {});
|
||||
}
|
||||
|
||||
if (this.data.optional.biography.keep)
|
||||
foundry.utils.setProperty(update, 'system.biography', this.actor.system.biography);
|
||||
|
||||
if (this.data.optional.inventory.keep) foundry.utils.setProperty(update, 'system.gold', this.actor.system.gold);
|
||||
|
||||
const { system, ...rest } = update;
|
||||
await this.actor.update({
|
||||
...rest,
|
||||
'==system': system ?? {}
|
||||
});
|
||||
|
||||
const inventoryItemTypes = ['weapon', 'armor', 'consumable', 'loot'];
|
||||
await this.actor.deleteEmbeddedDocuments(
|
||||
'Item',
|
||||
this.actor.items
|
||||
.filter(x => !inventoryItemTypes.includes(x.type) || !this.data.optional.inventory.keep)
|
||||
.map(x => x.id)
|
||||
);
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
@ -54,10 +54,9 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
|
||||
if (!config.roll.fate) return;
|
||||
|
||||
let returnMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.avoidScar');
|
||||
if (config.roll.fate.value <= this.actor.system.levelData.level.current) {
|
||||
// apply scarring - for now directly apply - later add a button.
|
||||
const newScarAmount = this.actor.system.scars + 1;
|
||||
|
||||
await this.actor.update({
|
||||
system: {
|
||||
scars: newScarAmount
|
||||
|
|
@ -65,13 +64,15 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
});
|
||||
|
||||
if (newScarAmount >= this.actor.system.resources.hope.max) {
|
||||
await this.actor.setDeathMoveDefeated(CONFIG.DH.GENERAL.defeatedConditionChoices.dead.id);
|
||||
return game.i18n.format('DAGGERHEART.UI.Chat.deathMove.journeysEnd', { scars: newScarAmount });
|
||||
}
|
||||
|
||||
return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.gainScar');
|
||||
returnMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.gainScar');
|
||||
}
|
||||
|
||||
return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.avoidScar');
|
||||
await this.actor.setDeathMoveDefeated(CONFIG.DH.GENERAL.defeatedConditionChoices.unconscious.id);
|
||||
return returnMessage;
|
||||
}
|
||||
|
||||
async handleRiskItAll() {
|
||||
|
|
@ -84,6 +85,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityDice'),
|
||||
actionType: null,
|
||||
advantage: null,
|
||||
grantResources: false,
|
||||
customConfig: { skips: { resources: true, reaction: true } }
|
||||
});
|
||||
|
||||
|
|
@ -118,6 +120,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
}
|
||||
|
||||
if (config.roll.result.duality == -1) {
|
||||
await this.actor.setDeathMoveDefeated(CONFIG.DH.GENERAL.defeatedConditionChoices.dead.id);
|
||||
chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllFailure');
|
||||
}
|
||||
|
||||
|
|
@ -141,6 +144,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
}
|
||||
]);
|
||||
|
||||
await this.actor.setDeathMoveDefeated(CONFIG.DH.GENERAL.defeatedConditionChoices.dead.id);
|
||||
return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.blazeOfGlory');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,10 @@ export default class DhlevelUpViewMode extends HandlebarsApplicationMixin(Applic
|
|||
return checkbox;
|
||||
});
|
||||
|
||||
let label = game.i18n.localize(option.label);
|
||||
let label =
|
||||
optionKey === 'domainCard'
|
||||
? game.i18n.format(option.label, { maxLevel: tier.levels.end })
|
||||
: game.i18n.localize(option.label);
|
||||
return {
|
||||
label: label,
|
||||
checkboxGroups: chunkify(checkboxes, option.minCost, chunkedBoxes => {
|
||||
|
|
|
|||
|
|
@ -669,26 +669,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
* 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)
|
||||
);
|
||||
new game.system.api.applications.dialogs.CharacterResetDialog(this.document).render({ force: true });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -753,8 +734,9 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
if (!result) return;
|
||||
|
||||
/* This could be avoided by baking config.costs into config.resourceUpdates. Didn't feel like messing with it at the time */
|
||||
const costResources = result.costs?.filter(x => x.enabled)
|
||||
.map(cost => ({ ...cost, value: -cost.value, total: -cost.total })) || {};
|
||||
const costResources =
|
||||
result.costs?.filter(x => x.enabled).map(cost => ({ ...cost, value: -cost.value, total: -cost.total })) ||
|
||||
{};
|
||||
config.resourceUpdates.addResources(costResources);
|
||||
await config.resourceUpdates.updateResources();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ export const defeatedConditions = () => {
|
|||
acc[key] = {
|
||||
...choice,
|
||||
img: defeated[`${choice.id}Icon`],
|
||||
description: `DAGGERHEART.CONFIG.Condition.${choice.id}.description`
|
||||
description: game.i18n.localize(`DAGGERHEART.CONFIG.Condition.${choice.id}.description`)
|
||||
};
|
||||
|
||||
return acc;
|
||||
|
|
@ -179,6 +179,10 @@ export const defeatedConditions = () => {
|
|||
};
|
||||
|
||||
export const defeatedConditionChoices = {
|
||||
deathMove: {
|
||||
id: 'deathMove',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.deathMove.name'
|
||||
},
|
||||
defeated: {
|
||||
id: 'defeated',
|
||||
name: 'DAGGERHEART.CONFIG.Condition.defeated.name'
|
||||
|
|
|
|||
|
|
@ -549,7 +549,18 @@ export default class DhCharacter extends BaseDataActor {
|
|||
}
|
||||
|
||||
get deathMoveViable() {
|
||||
return this.resources.hitPoints.max > 0 && this.resources.hitPoints.value >= this.resources.hitPoints.max;
|
||||
const { characterDefault } = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.Automation
|
||||
).defeated;
|
||||
const deathMoveOutcomeStatuses = Object.keys(CONFIG.DH.GENERAL.defeatedConditionChoices).filter(
|
||||
key => key !== characterDefault
|
||||
);
|
||||
const deathMoveNotResolved = this.parent.statuses.every(status => !deathMoveOutcomeStatuses.includes(status));
|
||||
|
||||
const allHitPointsMarked =
|
||||
this.resources.hitPoints.max > 0 && this.resources.hitPoints.value >= this.resources.hitPoints.max;
|
||||
return deathMoveNotResolved && allHitPointsMarked;
|
||||
}
|
||||
|
||||
get armorApplicableDamageTypes() {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export default class RegisteredTriggers extends Map {
|
|||
}
|
||||
|
||||
registerItemTriggers(item, registerOverride) {
|
||||
if (!item.actor || !item._stats.createdTime) return;
|
||||
for (const action of item.system.actions ?? []) {
|
||||
if (!action.actor) continue;
|
||||
|
||||
|
|
@ -71,10 +72,21 @@ export default class RegisteredTriggers extends Map {
|
|||
}
|
||||
}
|
||||
|
||||
unregisterSceneEnvironmentTriggers(flagSystemData) {
|
||||
const sceneData = new game.system.api.data.scenes.DHScene(flagSystemData);
|
||||
for (const environment of sceneData.sceneEnvironments) {
|
||||
if (environment.pack) continue;
|
||||
this.unregisterItemTriggers(environment.system.features);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterSceneTriggers(scene) {
|
||||
this.unregisterSceneEnvironmentTriggers(scene.flags.daggerheart);
|
||||
|
||||
for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) {
|
||||
const existingTrigger = this.get(triggerKey);
|
||||
if (!existingTrigger) continue;
|
||||
|
||||
const filtered = new Map();
|
||||
for (const [uuid, data] of existingTrigger.entries()) {
|
||||
if (!uuid.startsWith(scene.uuid)) filtered.set(uuid, data);
|
||||
|
|
@ -83,14 +95,17 @@ export default class RegisteredTriggers extends Map {
|
|||
}
|
||||
}
|
||||
|
||||
registerSceneEnvironmentTriggers(flagSystemData) {
|
||||
const sceneData = new game.system.api.data.scenes.DHScene(flagSystemData);
|
||||
for (const environment of sceneData.sceneEnvironments) {
|
||||
for (const feature of environment.system.features) {
|
||||
if (feature) this.registerItemTriggers(feature, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerSceneTriggers(scene) {
|
||||
/* TODO: Finish sceneEnvironment registration and unreg */
|
||||
// const systemData = new game.system.api.data.scenes.DHScene(scene.flags.daggerheart);
|
||||
// for (const environment of systemData.sceneEnvironments) {
|
||||
// for (const feature of environment.system.features) {
|
||||
// if(feature) this.registerItemTriggers(feature, true);
|
||||
// }
|
||||
// }
|
||||
this.registerSceneEnvironmentTriggers(scene.flags.daggerheart);
|
||||
|
||||
for (const actor of scene.tokens.filter(x => x.actor).map(x => x.actor)) {
|
||||
if (actor.prototypeToken.actorLink) continue;
|
||||
|
|
@ -107,13 +122,11 @@ export default class RegisteredTriggers extends Map {
|
|||
if (!triggerSettings.enabled) return updates;
|
||||
|
||||
const dualityTrigger = this.get(trigger);
|
||||
if (dualityTrigger) {
|
||||
const tokenBoundActors = ['adversary', 'environment'];
|
||||
const triggerActors = ['character', ...tokenBoundActors];
|
||||
if (dualityTrigger?.size) {
|
||||
const triggerActors = ['character', 'adversary', 'environment'];
|
||||
for (let [itemUuid, { actor: actorUuid, triggeringActorType, commands }] of dualityTrigger.entries()) {
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
if (!actor || !triggerActors.includes(actor.type)) continue;
|
||||
if (tokenBoundActors.includes(actor.type) && !actor.getActiveTokens().length) continue;
|
||||
|
||||
const triggerData = CONFIG.DH.TRIGGER.triggers[trigger];
|
||||
if (triggerData.usesActor && triggeringActorType !== 'any') {
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
defeated: new fields.SchemaField({
|
||||
enabled: new fields.BooleanField({
|
||||
required: true,
|
||||
initial: false,
|
||||
initial: true,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.enabled.label'
|
||||
}),
|
||||
overlay: new fields.BooleanField({
|
||||
|
|
@ -69,7 +69,7 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
characterDefault: new fields.StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
||||
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.unconscious.id,
|
||||
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.deathMove.id,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
|
||||
}),
|
||||
adversaryDefault: new fields.StringField({
|
||||
|
|
@ -84,23 +84,29 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.defeated.id,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
|
||||
}),
|
||||
deathMoveIcon: new fields.FilePathField({
|
||||
initial: 'icons/magic/life/heart-cross-purple-orange.webp',
|
||||
categories: ['IMAGE'],
|
||||
base64: false,
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.deathMove.label'
|
||||
}),
|
||||
deadIcon: new fields.FilePathField({
|
||||
initial: 'icons/magic/death/grave-tombstone-glow-teal.webp',
|
||||
categories: ['IMAGE'],
|
||||
base64: false,
|
||||
label: 'Dead'
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.dead.label'
|
||||
}),
|
||||
defeatedIcon: new fields.FilePathField({
|
||||
initial: 'icons/magic/control/fear-fright-mask-orange.webp',
|
||||
categories: ['IMAGE'],
|
||||
base64: false,
|
||||
label: 'Defeated'
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.defeated.label'
|
||||
}),
|
||||
unconsciousIcon: new fields.FilePathField({
|
||||
initial: 'icons/magic/control/sleep-bubble-purple.webp',
|
||||
categories: ['IMAGE'],
|
||||
base64: false,
|
||||
label: 'Unconcious'
|
||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.unconscious.label'
|
||||
})
|
||||
}),
|
||||
roll: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ export default class DualityRoll extends D20Roll {
|
|||
}
|
||||
|
||||
static async handleTriggers(roll, config) {
|
||||
if (!config.source?.actor) return;
|
||||
if (!config.source?.actor || config.skips?.triggers) return;
|
||||
|
||||
const updates = [];
|
||||
const dualityUpdates = await game.system.registeredTriggers.runTrigger(
|
||||
|
|
|
|||
|
|
@ -849,8 +849,8 @@ export default class DhpActor extends Actor {
|
|||
|
||||
async toggleDefeated(defeatedState) {
|
||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
||||
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions();
|
||||
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
|
||||
const { deathMove, unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions();
|
||||
const defeatedConditions = new Set([deathMove.id, unconscious.id, defeated.id, dead.id]);
|
||||
if (!defeatedState) {
|
||||
for (let defeatedId of defeatedConditions) {
|
||||
await this.toggleStatusEffect(defeatedId, { overlay: settings.overlay, active: defeatedState });
|
||||
|
|
@ -864,6 +864,18 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
async setDeathMoveDefeated(defeatedIconId) {
|
||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
||||
const actorDefault = settings[`${this.type}Default`];
|
||||
if (!settings.enabled || !settings.enabled || !actorDefault || actorDefault === defeatedIconId) return;
|
||||
|
||||
for (let defeatedId of Object.keys(CONFIG.DH.GENERAL.defeatedConditionChoices)) {
|
||||
await this.toggleStatusEffect(defeatedId, { overlay: settings.overlay, active: false });
|
||||
}
|
||||
|
||||
if (defeatedIconId) await this.toggleStatusEffect(defeatedIconId, { overlay: settings.overlay, active: true });
|
||||
}
|
||||
|
||||
queueScrollText(scrollingTextData) {
|
||||
this.#scrollTextQueue.push(...scrollingTextData.map(data => () => createScrollText(this, data)));
|
||||
if (!this.#scrollTextInterval) {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,27 @@ export default class DhScene extends Scene {
|
|||
}
|
||||
}
|
||||
|
||||
async _preUpdate(changes, options, user) {
|
||||
const allowed = await super._preUpdate(changes, options, user);
|
||||
if (allowed === false) return false;
|
||||
|
||||
if (changes.flags?.daggerheart) {
|
||||
if (this._source.flags.daggerheart) {
|
||||
const unregisterTriggerData = this._source.flags.daggerheart.sceneEnvironments.reduce(
|
||||
(acc, env) => {
|
||||
if (!changes.flags.daggerheart.sceneEnvironments.includes(env)) acc.sceneEnvironments.push(env);
|
||||
|
||||
return acc;
|
||||
},
|
||||
{ ...this._source.flags.daggerheart, sceneEnvironments: [] }
|
||||
);
|
||||
game.system.registeredTriggers.unregisterSceneEnvironmentTriggers(unregisterTriggerData);
|
||||
}
|
||||
|
||||
game.system.registeredTriggers.registerSceneEnvironmentTriggers(changes.flags.daggerheart);
|
||||
}
|
||||
}
|
||||
|
||||
_onDelete(options, userId) {
|
||||
super._onDelete(options, userId);
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ function getDualityMessage(roll, flavor) {
|
|||
${roll?.trait && abilities[roll.trait] ? `data-trait="${roll.trait}"` : ''}
|
||||
${roll?.advantage ? 'data-advantage="true"' : ''}
|
||||
${roll?.disadvantage ? 'data-disadvantage="true"' : ''}
|
||||
${roll?.grantResources ? 'data-grant-resources="true"' : ''}
|
||||
>
|
||||
${roll?.reaction ? '<i class="fa-solid fa-reply"></i>' : '<i class="fa-solid fa-circle-half-stroke"></i>'}
|
||||
${label}
|
||||
|
|
@ -63,7 +64,8 @@ export const renderDualityButton = async event => {
|
|||
traitValue = button.dataset.trait?.toLowerCase(),
|
||||
target = getCommandTarget({ allowNull: true }),
|
||||
difficulty = button.dataset.difficulty,
|
||||
advantage = button.dataset.advantage ? Number(button.dataset.advantage) : undefined;
|
||||
advantage = button.dataset.advantage ? Number(button.dataset.advantage) : undefined,
|
||||
grantResources = Boolean(button.dataset?.grantResources);
|
||||
|
||||
await enrichedDualityRoll(
|
||||
{
|
||||
|
|
@ -73,14 +75,15 @@ export const renderDualityButton = async event => {
|
|||
difficulty,
|
||||
title: button.dataset.title,
|
||||
label: button.dataset.label,
|
||||
advantage
|
||||
advantage,
|
||||
grantResources
|
||||
},
|
||||
event
|
||||
);
|
||||
};
|
||||
|
||||
export const enrichedDualityRoll = async (
|
||||
{ reaction, traitValue, target, difficulty, title, label, advantage, customConfig },
|
||||
{ reaction, traitValue, target, difficulty, title, label, advantage, grantResources, customConfig },
|
||||
event
|
||||
) => {
|
||||
const config = {
|
||||
|
|
@ -93,13 +96,18 @@ export const enrichedDualityRoll = async (
|
|||
advantage,
|
||||
type: reaction ? 'reaction' : null
|
||||
},
|
||||
skips: {
|
||||
resources: !grantResources,
|
||||
triggers: !grantResources
|
||||
},
|
||||
type: 'trait',
|
||||
hasRoll: true,
|
||||
...(customConfig ?? {})
|
||||
};
|
||||
|
||||
if (target) {
|
||||
await target.diceRoll(config);
|
||||
const result = await target.diceRoll(config);
|
||||
result.resourceUpdates.updateResources();
|
||||
} else {
|
||||
// For no target, call DualityRoll directly with basic data
|
||||
config.data = { experiences: {}, traits: {}, rules: {} };
|
||||
|
|
|
|||
|
|
@ -9,13 +9,47 @@
|
|||
"resource": {
|
||||
"type": "simple",
|
||||
"value": 0,
|
||||
"max": "",
|
||||
"icon": "",
|
||||
"recovery": null,
|
||||
"max": "@system.levelData.level.current",
|
||||
"icon": "fa-solid fa-water",
|
||||
"recovery": "session",
|
||||
"diceStates": {},
|
||||
"dieFaces": "d4"
|
||||
},
|
||||
"actions": {},
|
||||
"actions": {
|
||||
"tFlus34KotJjHfTe": {
|
||||
"type": "effect",
|
||||
"_id": "tFlus34KotJjHfTe",
|
||||
"systemPath": "actions",
|
||||
"baseAction": false,
|
||||
"description": "",
|
||||
"chatDisplay": true,
|
||||
"originItem": {
|
||||
"type": "itemCollection"
|
||||
},
|
||||
"actionType": "action",
|
||||
"triggers": [
|
||||
{
|
||||
"trigger": "fearRoll",
|
||||
"triggeringActorType": "self",
|
||||
"command": "const { max, value } = this.item.system.resource;\nconst maxValue = actor.system.levelData.level.current;\nconst afterUpdate = value+1;\nif (afterUpdate > maxValue) return;\n\nui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.knowTheTide'));\nreturn { updates: [{\n key: 'resource',\n itemId: this.item.id,\n target: this.item,\n value: 1,\n}]};"
|
||||
}
|
||||
],
|
||||
"cost": [],
|
||||
"uses": {
|
||||
"value": null,
|
||||
"max": "",
|
||||
"recovery": null,
|
||||
"consumeOnSuccess": false
|
||||
},
|
||||
"effects": [],
|
||||
"target": {
|
||||
"type": "any",
|
||||
"amount": null
|
||||
},
|
||||
"name": "Know The Tide",
|
||||
"range": ""
|
||||
}
|
||||
},
|
||||
"originItemType": null,
|
||||
"subType": null,
|
||||
"originId": null,
|
||||
|
|
|
|||
27
styles/less/dialog/character-reset/sheet.less
Normal file
27
styles/less/dialog/character-reset/sheet.less
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
.daggerheart.dh-style.dialog.views.character-reset {
|
||||
.character-reset-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
legend {
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.character-reset-header {
|
||||
font-size: var(--font-size-18);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.reset-data-container {
|
||||
display: grid;
|
||||
grid-template-columns: 3fr 2fr;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,3 +41,5 @@
|
|||
@import './settings/change-currency-icon.less';
|
||||
|
||||
@import './risk-it-all/sheet.less';
|
||||
|
||||
@import './character-reset/sheet.less';
|
||||
|
|
|
|||
33
templates/dialogs/characterReset.hbs
Normal file
33
templates/dialogs/characterReset.hbs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<div>
|
||||
<div class="character-reset-container">
|
||||
<div class="character-reset-header">{{localize "DAGGERHEART.APPLICATIONS.CharacterReset.headerTitle"}}</div>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterReset.alwaysDeleteSection"}} <i class="fa-solid fa-lock"></i></legend>
|
||||
|
||||
<div class="reset-data-wrapper two-columns even">
|
||||
{{#each this.data.delete as | data key|}}
|
||||
<div class="reset-data-container">
|
||||
<label>{{localize data.label}}</label>
|
||||
<input type="checkbox" {{checked data.keep}} disabled />
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterReset.optionalDeleteSection"}}</legend>
|
||||
|
||||
<div class="reset-data-wrapper two-columns even">
|
||||
{{#each this.data.optional as | data key|}}
|
||||
<div class="reset-data-container">
|
||||
<label>{{localize data.label}}</label>
|
||||
<input type="checkbox" name="{{concat "data.optional." key ".keep"}}" {{checked data.keep}} />
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<button type="button" data-action="finishSelection">{{localize "Reset"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -9,11 +9,12 @@
|
|||
</legend>
|
||||
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.enabled value=settingFields._source.defeated.enabled localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.overlay value=settingFields._source.defeated.overlay localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.overlay value=settingFields._source.defeated.overlay localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.characterDefault value=settingFields._source.defeated.characterDefault labelAttr="name" localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.adversaryDefault value=settingFields._source.defeated.adversaryDefault labelAttr="name" localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.companionDefault value=settingFields._source.defeated.companionDefault labelAttr="name" localize=true}}
|
||||
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.deathMoveIcon value=settingFields._source.defeated.deathMoveIcon localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.deadIcon value=settingFields._source.defeated.deadIcon localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.defeatedIcon value=settingFields._source.defeated.defeatedIcon localize=true}}
|
||||
{{formGroup settingFields.schema.fields.defeated.fields.unconsciousIcon value=settingFields._source.defeated.unconsciousIcon localize=true}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue