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
|
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
|
||||||
: undefined;
|
: undefined;
|
||||||
const difficulty = rollCommand.difficulty;
|
const difficulty = rollCommand.difficulty;
|
||||||
|
const grantResources = Boolean(rollCommand.grantResources);
|
||||||
|
|
||||||
const target = getCommandTarget({ allowNull: true });
|
const target = getCommandTarget({ allowNull: true });
|
||||||
const title =
|
const title =
|
||||||
|
|
@ -324,7 +325,8 @@ Hooks.on('chatMessage', (_, message) => {
|
||||||
title,
|
title,
|
||||||
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'),
|
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'),
|
||||||
actionType: null,
|
actionType: null,
|
||||||
advantage
|
advantage,
|
||||||
|
grantResources
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
lang/en.json
20
lang/en.json
|
|
@ -330,6 +330,12 @@
|
||||||
"title": "{actor} - Character Setup",
|
"title": "{actor} - Character Setup",
|
||||||
"traitIncreases": "Trait Increases"
|
"traitIncreases": "Trait Increases"
|
||||||
},
|
},
|
||||||
|
"CharacterReset": {
|
||||||
|
"title": "Reset Character",
|
||||||
|
"alwaysDeleteSection": "Deleted Data",
|
||||||
|
"optionalDeleteSection": "Optional Data",
|
||||||
|
"headerTitle": "Select which data you'd like to keep"
|
||||||
|
},
|
||||||
"CombatTracker": {
|
"CombatTracker": {
|
||||||
"combatStarted": "Active",
|
"combatStarted": "Active",
|
||||||
"giveSpotlight": "Give The Spotlight",
|
"giveSpotlight": "Give The Spotlight",
|
||||||
|
|
@ -974,6 +980,10 @@
|
||||||
"outsideRange": "Outside Range"
|
"outsideRange": "Outside Range"
|
||||||
},
|
},
|
||||||
"Condition": {
|
"Condition": {
|
||||||
|
"deathMove": {
|
||||||
|
"name": "Death Move",
|
||||||
|
"description": "The character is about to make a Death Move"
|
||||||
|
},
|
||||||
"dead": {
|
"dead": {
|
||||||
"name": "Dead",
|
"name": "Dead",
|
||||||
"description": "The character is dead"
|
"description": "The character is dead"
|
||||||
|
|
@ -2211,6 +2221,7 @@
|
||||||
"single": "Player",
|
"single": "Player",
|
||||||
"plurial": "Players"
|
"plurial": "Players"
|
||||||
},
|
},
|
||||||
|
"portrait": "Portrait",
|
||||||
"proficiency": "Proficiency",
|
"proficiency": "Proficiency",
|
||||||
"quantity": "Quantity",
|
"quantity": "Quantity",
|
||||||
"range": "Range",
|
"range": "Range",
|
||||||
|
|
@ -2442,7 +2453,11 @@
|
||||||
"overlay": { "label": "Overlay Effect" },
|
"overlay": { "label": "Overlay Effect" },
|
||||||
"characterDefault": { "label": "Character Default Defeated Status" },
|
"characterDefault": { "label": "Character Default Defeated Status" },
|
||||||
"adversaryDefault": { "label": "Adversary 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": {
|
"hopeFear": {
|
||||||
"label": "Hope & Fear",
|
"label": "Hope & Fear",
|
||||||
|
|
@ -2876,7 +2891,8 @@
|
||||||
"documentIsMissing": "The {documentType} is missing from the world.",
|
"documentIsMissing": "The {documentType} is missing from the world.",
|
||||||
"tokenActorMissing": "{name} is missing an Actor",
|
"tokenActorMissing": "{name} is missing an Actor",
|
||||||
"tokenActorsMissing": "[{names}] missing Actors",
|
"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": {
|
"Sidebar": {
|
||||||
"actorDirectory": {
|
"actorDirectory": {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
export { default as AttributionDialog } from './attributionDialog.mjs';
|
export { default as AttributionDialog } from './attributionDialog.mjs';
|
||||||
export { default as BeastformDialog } from './beastformDialog.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 d20RollDialog } from './d20RollDialog.mjs';
|
||||||
export { default as DamageDialog } from './damageDialog.mjs';
|
export { default as DamageDialog } from './damageDialog.mjs';
|
||||||
export { default as DamageReductionDialog } from './damageReductionDialog.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;
|
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) {
|
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;
|
const newScarAmount = this.actor.system.scars + 1;
|
||||||
|
|
||||||
await this.actor.update({
|
await this.actor.update({
|
||||||
system: {
|
system: {
|
||||||
scars: newScarAmount
|
scars: newScarAmount
|
||||||
|
|
@ -65,13 +64,15 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newScarAmount >= this.actor.system.resources.hope.max) {
|
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.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() {
|
async handleRiskItAll() {
|
||||||
|
|
@ -84,6 +85,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,
|
||||||
|
grantResources: false,
|
||||||
customConfig: { skips: { resources: true, reaction: true } }
|
customConfig: { skips: { resources: true, reaction: true } }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -118,6 +120,7 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.roll.result.duality == -1) {
|
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');
|
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');
|
return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.blazeOfGlory');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,10 @@ export default class DhlevelUpViewMode extends HandlebarsApplicationMixin(Applic
|
||||||
return checkbox;
|
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 {
|
return {
|
||||||
label: label,
|
label: label,
|
||||||
checkboxGroups: chunkify(checkboxes, option.minCost, chunkedBoxes => {
|
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.
|
* Resets the character data and removes all embedded documents.
|
||||||
*/
|
*/
|
||||||
static async #resetCharacter() {
|
static async #resetCharacter() {
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
new game.system.api.applications.dialogs.CharacterResetDialog(this.document).render({ force: true });
|
||||||
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)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -753,8 +734,9 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
|
|
||||||
/* This could be avoided by baking config.costs into config.resourceUpdates. Didn't feel like messing with it at the time */
|
/* 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)
|
const costResources =
|
||||||
.map(cost => ({ ...cost, value: -cost.value, total: -cost.total })) || {};
|
result.costs?.filter(x => x.enabled).map(cost => ({ ...cost, value: -cost.value, total: -cost.total })) ||
|
||||||
|
{};
|
||||||
config.resourceUpdates.addResources(costResources);
|
config.resourceUpdates.addResources(costResources);
|
||||||
await config.resourceUpdates.updateResources();
|
await config.resourceUpdates.updateResources();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ export const defeatedConditions = () => {
|
||||||
acc[key] = {
|
acc[key] = {
|
||||||
...choice,
|
...choice,
|
||||||
img: defeated[`${choice.id}Icon`],
|
img: defeated[`${choice.id}Icon`],
|
||||||
description: `DAGGERHEART.CONFIG.Condition.${choice.id}.description`
|
description: game.i18n.localize(`DAGGERHEART.CONFIG.Condition.${choice.id}.description`)
|
||||||
};
|
};
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
|
|
@ -179,6 +179,10 @@ export const defeatedConditions = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const defeatedConditionChoices = {
|
export const defeatedConditionChoices = {
|
||||||
|
deathMove: {
|
||||||
|
id: 'deathMove',
|
||||||
|
name: 'DAGGERHEART.CONFIG.Condition.deathMove.name'
|
||||||
|
},
|
||||||
defeated: {
|
defeated: {
|
||||||
id: 'defeated',
|
id: 'defeated',
|
||||||
name: 'DAGGERHEART.CONFIG.Condition.defeated.name'
|
name: 'DAGGERHEART.CONFIG.Condition.defeated.name'
|
||||||
|
|
|
||||||
|
|
@ -549,7 +549,18 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
}
|
}
|
||||||
|
|
||||||
get deathMoveViable() {
|
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() {
|
get armorApplicableDamageTypes() {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ export default class RegisteredTriggers extends Map {
|
||||||
}
|
}
|
||||||
|
|
||||||
registerItemTriggers(item, registerOverride) {
|
registerItemTriggers(item, registerOverride) {
|
||||||
|
if (!item.actor || !item._stats.createdTime) return;
|
||||||
for (const action of item.system.actions ?? []) {
|
for (const action of item.system.actions ?? []) {
|
||||||
if (!action.actor) continue;
|
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) {
|
unregisterSceneTriggers(scene) {
|
||||||
|
this.unregisterSceneEnvironmentTriggers(scene.flags.daggerheart);
|
||||||
|
|
||||||
for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) {
|
for (const triggerKey of Object.keys(CONFIG.DH.TRIGGER.triggers)) {
|
||||||
const existingTrigger = this.get(triggerKey);
|
const existingTrigger = this.get(triggerKey);
|
||||||
if (!existingTrigger) continue;
|
if (!existingTrigger) continue;
|
||||||
|
|
||||||
const filtered = new Map();
|
const filtered = new Map();
|
||||||
for (const [uuid, data] of existingTrigger.entries()) {
|
for (const [uuid, data] of existingTrigger.entries()) {
|
||||||
if (!uuid.startsWith(scene.uuid)) filtered.set(uuid, data);
|
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) {
|
registerSceneTriggers(scene) {
|
||||||
/* TODO: Finish sceneEnvironment registration and unreg */
|
this.registerSceneEnvironmentTriggers(scene.flags.daggerheart);
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (const actor of scene.tokens.filter(x => x.actor).map(x => x.actor)) {
|
for (const actor of scene.tokens.filter(x => x.actor).map(x => x.actor)) {
|
||||||
if (actor.prototypeToken.actorLink) continue;
|
if (actor.prototypeToken.actorLink) continue;
|
||||||
|
|
@ -107,13 +122,11 @@ export default class RegisteredTriggers extends Map {
|
||||||
if (!triggerSettings.enabled) return updates;
|
if (!triggerSettings.enabled) return updates;
|
||||||
|
|
||||||
const dualityTrigger = this.get(trigger);
|
const dualityTrigger = this.get(trigger);
|
||||||
if (dualityTrigger) {
|
if (dualityTrigger?.size) {
|
||||||
const tokenBoundActors = ['adversary', 'environment'];
|
const triggerActors = ['character', 'adversary', 'environment'];
|
||||||
const triggerActors = ['character', ...tokenBoundActors];
|
|
||||||
for (let [itemUuid, { actor: actorUuid, triggeringActorType, commands }] of dualityTrigger.entries()) {
|
for (let [itemUuid, { actor: actorUuid, triggeringActorType, commands }] of dualityTrigger.entries()) {
|
||||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||||
if (!actor || !triggerActors.includes(actor.type)) continue;
|
if (!actor || !triggerActors.includes(actor.type)) continue;
|
||||||
if (tokenBoundActors.includes(actor.type) && !actor.getActiveTokens().length) continue;
|
|
||||||
|
|
||||||
const triggerData = CONFIG.DH.TRIGGER.triggers[trigger];
|
const triggerData = CONFIG.DH.TRIGGER.triggers[trigger];
|
||||||
if (triggerData.usesActor && triggeringActorType !== 'any') {
|
if (triggerData.usesActor && triggeringActorType !== 'any') {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
||||||
defeated: new fields.SchemaField({
|
defeated: new fields.SchemaField({
|
||||||
enabled: new fields.BooleanField({
|
enabled: new fields.BooleanField({
|
||||||
required: true,
|
required: true,
|
||||||
initial: false,
|
initial: true,
|
||||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.enabled.label'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.enabled.label'
|
||||||
}),
|
}),
|
||||||
overlay: new fields.BooleanField({
|
overlay: new fields.BooleanField({
|
||||||
|
|
@ -69,7 +69,7 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
||||||
characterDefault: new fields.StringField({
|
characterDefault: new fields.StringField({
|
||||||
required: true,
|
required: true,
|
||||||
choices: CONFIG.DH.GENERAL.defeatedConditionChoices,
|
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'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.characterDefault.label'
|
||||||
}),
|
}),
|
||||||
adversaryDefault: new fields.StringField({
|
adversaryDefault: new fields.StringField({
|
||||||
|
|
@ -84,23 +84,29 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
||||||
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.defeated.id,
|
initial: CONFIG.DH.GENERAL.defeatedConditionChoices.defeated.id,
|
||||||
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.companionDefault.label'
|
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({
|
deadIcon: new fields.FilePathField({
|
||||||
initial: 'icons/magic/death/grave-tombstone-glow-teal.webp',
|
initial: 'icons/magic/death/grave-tombstone-glow-teal.webp',
|
||||||
categories: ['IMAGE'],
|
categories: ['IMAGE'],
|
||||||
base64: false,
|
base64: false,
|
||||||
label: 'Dead'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.dead.label'
|
||||||
}),
|
}),
|
||||||
defeatedIcon: new fields.FilePathField({
|
defeatedIcon: new fields.FilePathField({
|
||||||
initial: 'icons/magic/control/fear-fright-mask-orange.webp',
|
initial: 'icons/magic/control/fear-fright-mask-orange.webp',
|
||||||
categories: ['IMAGE'],
|
categories: ['IMAGE'],
|
||||||
base64: false,
|
base64: false,
|
||||||
label: 'Defeated'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.defeated.label'
|
||||||
}),
|
}),
|
||||||
unconsciousIcon: new fields.FilePathField({
|
unconsciousIcon: new fields.FilePathField({
|
||||||
initial: 'icons/magic/control/sleep-bubble-purple.webp',
|
initial: 'icons/magic/control/sleep-bubble-purple.webp',
|
||||||
categories: ['IMAGE'],
|
categories: ['IMAGE'],
|
||||||
base64: false,
|
base64: false,
|
||||||
label: 'Unconcious'
|
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.defeated.unconscious.label'
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
roll: new fields.SchemaField({
|
roll: new fields.SchemaField({
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,7 @@ export default class DualityRoll extends D20Roll {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async handleTriggers(roll, config) {
|
static async handleTriggers(roll, config) {
|
||||||
if (!config.source?.actor) return;
|
if (!config.source?.actor || config.skips?.triggers) return;
|
||||||
|
|
||||||
const updates = [];
|
const updates = [];
|
||||||
const dualityUpdates = await game.system.registeredTriggers.runTrigger(
|
const dualityUpdates = await game.system.registeredTriggers.runTrigger(
|
||||||
|
|
|
||||||
|
|
@ -849,8 +849,8 @@ export default class DhpActor extends Actor {
|
||||||
|
|
||||||
async toggleDefeated(defeatedState) {
|
async toggleDefeated(defeatedState) {
|
||||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).defeated;
|
||||||
const { unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions();
|
const { deathMove, unconscious, defeated, dead } = CONFIG.DH.GENERAL.conditions();
|
||||||
const defeatedConditions = new Set([unconscious.id, defeated.id, dead.id]);
|
const defeatedConditions = new Set([deathMove.id, unconscious.id, defeated.id, dead.id]);
|
||||||
if (!defeatedState) {
|
if (!defeatedState) {
|
||||||
for (let defeatedId of defeatedConditions) {
|
for (let defeatedId of defeatedConditions) {
|
||||||
await this.toggleStatusEffect(defeatedId, { overlay: settings.overlay, active: defeatedState });
|
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) {
|
queueScrollText(scrollingTextData) {
|
||||||
this.#scrollTextQueue.push(...scrollingTextData.map(data => () => createScrollText(this, data)));
|
this.#scrollTextQueue.push(...scrollingTextData.map(data => () => createScrollText(this, data)));
|
||||||
if (!this.#scrollTextInterval) {
|
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) {
|
_onDelete(options, userId) {
|
||||||
super._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?.trait && abilities[roll.trait] ? `data-trait="${roll.trait}"` : ''}
|
||||||
${roll?.advantage ? 'data-advantage="true"' : ''}
|
${roll?.advantage ? 'data-advantage="true"' : ''}
|
||||||
${roll?.disadvantage ? 'data-disadvantage="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>'}
|
${roll?.reaction ? '<i class="fa-solid fa-reply"></i>' : '<i class="fa-solid fa-circle-half-stroke"></i>'}
|
||||||
${label}
|
${label}
|
||||||
|
|
@ -63,7 +64,8 @@ export const renderDualityButton = async event => {
|
||||||
traitValue = button.dataset.trait?.toLowerCase(),
|
traitValue = button.dataset.trait?.toLowerCase(),
|
||||||
target = getCommandTarget({ allowNull: true }),
|
target = getCommandTarget({ allowNull: true }),
|
||||||
difficulty = button.dataset.difficulty,
|
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(
|
await enrichedDualityRoll(
|
||||||
{
|
{
|
||||||
|
|
@ -73,14 +75,15 @@ export const renderDualityButton = async event => {
|
||||||
difficulty,
|
difficulty,
|
||||||
title: button.dataset.title,
|
title: button.dataset.title,
|
||||||
label: button.dataset.label,
|
label: button.dataset.label,
|
||||||
advantage
|
advantage,
|
||||||
|
grantResources
|
||||||
},
|
},
|
||||||
event
|
event
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const enrichedDualityRoll = async (
|
export const enrichedDualityRoll = async (
|
||||||
{ reaction, traitValue, target, difficulty, title, label, advantage, customConfig },
|
{ reaction, traitValue, target, difficulty, title, label, advantage, grantResources, customConfig },
|
||||||
event
|
event
|
||||||
) => {
|
) => {
|
||||||
const config = {
|
const config = {
|
||||||
|
|
@ -93,13 +96,18 @@ export const enrichedDualityRoll = async (
|
||||||
advantage,
|
advantage,
|
||||||
type: reaction ? 'reaction' : null
|
type: reaction ? 'reaction' : null
|
||||||
},
|
},
|
||||||
|
skips: {
|
||||||
|
resources: !grantResources,
|
||||||
|
triggers: !grantResources
|
||||||
|
},
|
||||||
type: 'trait',
|
type: 'trait',
|
||||||
hasRoll: true,
|
hasRoll: true,
|
||||||
...(customConfig ?? {})
|
...(customConfig ?? {})
|
||||||
};
|
};
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
await target.diceRoll(config);
|
const result = await target.diceRoll(config);
|
||||||
|
result.resourceUpdates.updateResources();
|
||||||
} else {
|
} else {
|
||||||
// For no target, call DualityRoll directly with basic data
|
// For no target, call DualityRoll directly with basic data
|
||||||
config.data = { experiences: {}, traits: {}, rules: {} };
|
config.data = { experiences: {}, traits: {}, rules: {} };
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,47 @@
|
||||||
"resource": {
|
"resource": {
|
||||||
"type": "simple",
|
"type": "simple",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"max": "",
|
"max": "@system.levelData.level.current",
|
||||||
"icon": "",
|
"icon": "fa-solid fa-water",
|
||||||
"recovery": null,
|
"recovery": "session",
|
||||||
"diceStates": {},
|
"diceStates": {},
|
||||||
"dieFaces": "d4"
|
"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,
|
"originItemType": null,
|
||||||
"subType": null,
|
"subType": null,
|
||||||
"originId": 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 './settings/change-currency-icon.less';
|
||||||
|
|
||||||
@import './risk-it-all/sheet.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>
|
</legend>
|
||||||
|
|
||||||
{{formGroup settingFields.schema.fields.defeated.fields.enabled value=settingFields._source.defeated.enabled localize=true}}
|
{{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.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.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.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.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.defeatedIcon value=settingFields._source.defeated.defeatedIcon localize=true}}
|
||||||
{{formGroup settingFields.schema.fields.defeated.fields.unconsciousIcon value=settingFields._source.defeated.unconsciousIcon 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