mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 14:36:13 +01:00
Merge branch 'main' into release
This commit is contained in:
commit
35bceac520
58 changed files with 1075 additions and 286 deletions
3
.editorconfig
Normal file
3
.editorconfig
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[*]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = spaces
|
||||||
|
|
@ -242,6 +242,38 @@ Hooks.on('setup', () => {
|
||||||
systemEffect: true
|
systemEffect: true
|
||||||
}))
|
}))
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const actorCommon = {
|
||||||
|
bar: ['resources.stress'],
|
||||||
|
value: []
|
||||||
|
};
|
||||||
|
const damageThresholds = ['damageThresholds.major', 'damageThresholds.severe'];
|
||||||
|
const traits = Object.keys(game.system.api.data.actors.DhCharacter.schema.fields.traits.fields).map(
|
||||||
|
trait => `traits.${trait}.value`
|
||||||
|
);
|
||||||
|
CONFIG.Actor.trackableAttributes = {
|
||||||
|
character: {
|
||||||
|
bar: [...actorCommon.bar, 'resources.hitPoints', 'resources.hope'],
|
||||||
|
value: [
|
||||||
|
...actorCommon.value,
|
||||||
|
...traits,
|
||||||
|
...damageThresholds,
|
||||||
|
'proficiency',
|
||||||
|
'evasion',
|
||||||
|
'armorScore',
|
||||||
|
'scars',
|
||||||
|
'levelData.level.current'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
adversary: {
|
||||||
|
bar: [...actorCommon.bar, 'resources.hitPoints'],
|
||||||
|
value: [...actorCommon.value, ...damageThresholds, 'criticalThreshold']
|
||||||
|
},
|
||||||
|
companion: {
|
||||||
|
bar: [...actorCommon.bar],
|
||||||
|
value: [...actorCommon.value, 'evasion', 'levelData.level.current']
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('ready', async () => {
|
Hooks.on('ready', async () => {
|
||||||
|
|
|
||||||
72
lang/en.json
72
lang/en.json
|
|
@ -192,6 +192,9 @@
|
||||||
},
|
},
|
||||||
"age": "Age",
|
"age": "Age",
|
||||||
"backgroundQuestions": "Backgrounds",
|
"backgroundQuestions": "Backgrounds",
|
||||||
|
"burden": {
|
||||||
|
"ignore": { "label": "Burden: Ignore", "hint": "Ignore burden rules" }
|
||||||
|
},
|
||||||
"companionFeatures": "Companion Features",
|
"companionFeatures": "Companion Features",
|
||||||
"connections": "Connections",
|
"connections": "Connections",
|
||||||
"contextMenu": {
|
"contextMenu": {
|
||||||
|
|
@ -214,6 +217,12 @@
|
||||||
"maxEvasionBonus": "Max Evasion Increase",
|
"maxEvasionBonus": "Max Evasion Increase",
|
||||||
"maxHPBonus": "Max HP Increase",
|
"maxHPBonus": "Max HP Increase",
|
||||||
"pronouns": "Pronouns",
|
"pronouns": "Pronouns",
|
||||||
|
"roll": {
|
||||||
|
"guaranteedCritical": {
|
||||||
|
"label": "Guaranteed Critical",
|
||||||
|
"hint": "Set to 1 to always roll a critical"
|
||||||
|
}
|
||||||
|
},
|
||||||
"story": {
|
"story": {
|
||||||
"backgroundTitle": "Background",
|
"backgroundTitle": "Background",
|
||||||
"characteristics": "Characteristics",
|
"characteristics": "Characteristics",
|
||||||
|
|
@ -343,6 +352,11 @@
|
||||||
"requestSpotlight": "Request The Spotlight",
|
"requestSpotlight": "Request The Spotlight",
|
||||||
"openCountdowns": "Countdowns"
|
"openCountdowns": "Countdowns"
|
||||||
},
|
},
|
||||||
|
"CompendiumBrowserSettings": {
|
||||||
|
"title": "Enable Compendiums",
|
||||||
|
"enableSource": "Enable Source",
|
||||||
|
"disableSource": "Disable Source"
|
||||||
|
},
|
||||||
"ContextMenu": {
|
"ContextMenu": {
|
||||||
"disableEffect": "Disable Effect",
|
"disableEffect": "Disable Effect",
|
||||||
"enableEffect": "Enable Effect",
|
"enableEffect": "Enable Effect",
|
||||||
|
|
@ -446,6 +460,10 @@
|
||||||
"description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.",
|
"description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.",
|
||||||
"name": "Prepare"
|
"name": "Prepare"
|
||||||
},
|
},
|
||||||
|
"prepareWithFriends": {
|
||||||
|
"description": "Describe how you are preparing for the next day's adventure, then gain a Hope. If you choose to Prepare with one or more members of your party, you may each take two Hope.",
|
||||||
|
"name": "Prepare (with Friends)"
|
||||||
|
},
|
||||||
"repairArmor": {
|
"repairArmor": {
|
||||||
"description": "Describe how you spend time repairing your armor and clear all of its Armor Slots. You may also do this to an ally's armor instead.",
|
"description": "Describe how you spend time repairing your armor and clear all of its Armor Slots. You may also do this to an ally's armor instead.",
|
||||||
"name": "Repair Armor"
|
"name": "Repair Armor"
|
||||||
|
|
@ -477,6 +495,10 @@
|
||||||
"prepare": {
|
"prepare": {
|
||||||
"name": "Prepare",
|
"name": "Prepare",
|
||||||
"description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope."
|
"description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope."
|
||||||
|
},
|
||||||
|
"prepareWithFriends": {
|
||||||
|
"name": "Prepare (with Friends)",
|
||||||
|
"description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"refreshable": {
|
"refreshable": {
|
||||||
|
|
@ -1840,6 +1862,16 @@
|
||||||
"singular": "Adversary",
|
"singular": "Adversary",
|
||||||
"plural": "Adversaries"
|
"plural": "Adversaries"
|
||||||
},
|
},
|
||||||
|
"Attack": {
|
||||||
|
"hpDamageMultiplier": {
|
||||||
|
"label": "HP Damage Multiplier",
|
||||||
|
"hint": "Multiply any damage you deal by this number"
|
||||||
|
},
|
||||||
|
"hpDamageTakenMultiplier": {
|
||||||
|
"label": "HP Damage Taken Multiplier",
|
||||||
|
"hint": "Multiply any damage dealt to you by this number"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Bonuses": {
|
"Bonuses": {
|
||||||
"rest": {
|
"rest": {
|
||||||
"downtimeAction": "Downtime Action",
|
"downtimeAction": "Downtime Action",
|
||||||
|
|
@ -2024,16 +2056,40 @@
|
||||||
"reaction": "Reaction Roll"
|
"reaction": "Reaction Roll"
|
||||||
},
|
},
|
||||||
"Rules": {
|
"Rules": {
|
||||||
|
"conditionImmunities": {
|
||||||
|
"hidden": "Condition Immunity: Hidden",
|
||||||
|
"restrained": "Condition Immunity: Restrained",
|
||||||
|
"vulnerable": "Condition Immunity: Vulnerable"
|
||||||
|
},
|
||||||
"damageReduction": {
|
"damageReduction": {
|
||||||
|
"disabledArmor": { "label": "Disabled Armorslots" },
|
||||||
"increasePerArmorMark": {
|
"increasePerArmorMark": {
|
||||||
"label": "Damage Reduction per Armor Slot",
|
"label": "Damage Reduction per Armor Slot",
|
||||||
"hint": "A used armor slot normally reduces damage by one step. This value increases the number of steps damage is reduced by."
|
"hint": "A used armor slot normally reduces damage by one step. This value increases the number of steps damage is reduced by."
|
||||||
},
|
},
|
||||||
|
"magical": {
|
||||||
|
"label": "Daamge Reduction: Only Magical",
|
||||||
|
"hint": "Armor can only be used to reduce magical damage"
|
||||||
|
},
|
||||||
"maxArmorMarkedBonus": "Max Armor Used",
|
"maxArmorMarkedBonus": "Max Armor Used",
|
||||||
"maxArmorMarkedStress": {
|
"maxArmorMarkedStress": {
|
||||||
"label": "Max Armor Used With Stress",
|
"label": "Max Armor Used With Stress",
|
||||||
"hint": "If this value is set you can use up to that much stress to spend additional Armor Marks beyond your normal maximum."
|
"hint": "If this value is set you can use up to that much stress to spend additional Armor Marks beyond your normal maximum."
|
||||||
},
|
},
|
||||||
|
"reduceSeverity": {
|
||||||
|
"magical": {
|
||||||
|
"label": "Reduce Damage Severity: Magical",
|
||||||
|
"hint": "Lowers any magical damage received by the set amount of severity degrees"
|
||||||
|
},
|
||||||
|
"physical": {
|
||||||
|
"label": "Reduce Damage Severity: Physical",
|
||||||
|
"hint": "Lowers any physical damage received by the set amount of severity degrees"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"physical": {
|
||||||
|
"label": "Damage Reduction: Only Physical",
|
||||||
|
"hint": "Armor can only be used to reduce physical damage"
|
||||||
|
},
|
||||||
"stress": {
|
"stress": {
|
||||||
"any": {
|
"any": {
|
||||||
"label": "Stress Damage Reduction: Any",
|
"label": "Stress Damage Reduction: Any",
|
||||||
|
|
@ -2051,6 +2107,12 @@
|
||||||
"label": "Stress Damage Reduction: Minor",
|
"label": "Stress Damage Reduction: Minor",
|
||||||
"hint": "The cost in stress you can pay to reduce minor damage to none."
|
"hint": "The cost in stress you can pay to reduce minor damage to none."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"thresholdImmunities": {
|
||||||
|
"minor": {
|
||||||
|
"label": "Threshold Immunities: Minor",
|
||||||
|
"hint": "Automatically ignores minor damage"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"attack": {
|
"attack": {
|
||||||
|
|
@ -2120,7 +2182,9 @@
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
"base": "Base",
|
"base": "Base",
|
||||||
"triggers": "Triggers",
|
"triggers": "Triggers",
|
||||||
"deathMoves": "Deathmoves"
|
"deathMoves": "Deathmoves",
|
||||||
|
"sources": "Sources",
|
||||||
|
"packs": "Packs"
|
||||||
},
|
},
|
||||||
"Tiers": {
|
"Tiers": {
|
||||||
"singular": "Tier",
|
"singular": "Tier",
|
||||||
|
|
@ -2152,6 +2216,7 @@
|
||||||
"continue": "Continue",
|
"continue": "Continue",
|
||||||
"criticalSuccess": "Critical Success",
|
"criticalSuccess": "Critical Success",
|
||||||
"criticalShort": "Critical",
|
"criticalShort": "Critical",
|
||||||
|
"currentLevel": "Current Level",
|
||||||
"custom": "Custom",
|
"custom": "Custom",
|
||||||
"d20Roll": "D20 Roll",
|
"d20Roll": "D20 Roll",
|
||||||
"damage": "Damage",
|
"damage": "Damage",
|
||||||
|
|
@ -2555,6 +2620,8 @@
|
||||||
"resetMovesTitle": "Reset {type} Downtime Moves",
|
"resetMovesTitle": "Reset {type} Downtime Moves",
|
||||||
"resetItemFeaturesTitle": "Reset {type}",
|
"resetItemFeaturesTitle": "Reset {type}",
|
||||||
"resetMovesText": "Are you sure you want to reset?",
|
"resetMovesText": "Are you sure you want to reset?",
|
||||||
|
"deleteItemTitle": "Delete Homebrew Item",
|
||||||
|
"deleteItemText": "Are you sure you want to delete the item?",
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
"maxFear": { "label": "Max Fear" },
|
"maxFear": { "label": "Max Fear" },
|
||||||
"maxHope": { "label": "Max Hope" },
|
"maxHope": { "label": "Max Hope" },
|
||||||
|
|
@ -2786,6 +2853,7 @@
|
||||||
"ItemBrowser": {
|
"ItemBrowser": {
|
||||||
"title": "Daggerheart Compendium Browser",
|
"title": "Daggerheart Compendium Browser",
|
||||||
"hint": "Select a Folder in sidebar to start browsing through the compendium",
|
"hint": "Select a Folder in sidebar to start browsing through the compendium",
|
||||||
|
"browserSettings": "Browser Settings",
|
||||||
"searchPlaceholder": "Search...",
|
"searchPlaceholder": "Search...",
|
||||||
"columnName": "Name",
|
"columnName": "Name",
|
||||||
"tooltipFilters": "Filters",
|
"tooltipFilters": "Filters",
|
||||||
|
|
@ -2942,7 +3010,7 @@
|
||||||
"rulesOn": "Rules On",
|
"rulesOn": "Rules On",
|
||||||
"rulesOff": "Rules Off",
|
"rulesOff": "Rules Off",
|
||||||
"remainingUses": "Uses refresh on {type}",
|
"remainingUses": "Uses refresh on {type}",
|
||||||
"rightClickExtand": "Right-Click to extand",
|
"rightClickExtend": "Right-Click to extend",
|
||||||
"companionPartnerLevelBlock": "The companion needs an assigned partner to level up.",
|
"companionPartnerLevelBlock": "The companion needs an assigned partner to level up.",
|
||||||
"configureAttribution": "Configure Attribution",
|
"configureAttribution": "Configure Attribution",
|
||||||
"deleteItem": "Delete Item",
|
"deleteItem": "Delete Item",
|
||||||
|
|
|
||||||
136
module/applications/dialogs/CompendiumBrowserSettings.mjs
Normal file
136
module/applications/dialogs/CompendiumBrowserSettings.mjs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class CompendiumBrowserSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.browserSettings = game.settings
|
||||||
|
.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings)
|
||||||
|
.toObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'div',
|
||||||
|
classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'compendium-brower-settings'],
|
||||||
|
window: {
|
||||||
|
icon: 'fa-solid fa-book',
|
||||||
|
title: 'DAGGERHEART.APPLICATIONS.CompendiumBrowserSettings.title'
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: 500
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
toggleSource: CompendiumBrowserSettings.#toggleSource,
|
||||||
|
finish: CompendiumBrowserSettings.#finish
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
packs: {
|
||||||
|
id: 'packs',
|
||||||
|
template: 'systems/daggerheart/templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs'
|
||||||
|
},
|
||||||
|
footer: { template: 'systems/daggerheart/templates/dialogs/compendiumBrowserSettingsDialog/footer.hbs' }
|
||||||
|
};
|
||||||
|
|
||||||
|
static #browserPackTypes = ['Actor', 'Item'];
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
for (const element of htmlElement.querySelectorAll('.pack-checkbox'))
|
||||||
|
element.addEventListener('change', this.toggleTypedPack.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
|
||||||
|
const excludedSourceData = this.browserSettings.excludedSources;
|
||||||
|
const excludedPackData = this.browserSettings.excludedPacks;
|
||||||
|
context.typePackCollections = game.packs.reduce((acc, pack) => {
|
||||||
|
const { type, label, packageType, packageName, id } = pack.metadata;
|
||||||
|
if (packageType === 'world' || !CompendiumBrowserSettings.#browserPackTypes.includes(type)) return acc;
|
||||||
|
|
||||||
|
const sourceChecked =
|
||||||
|
!excludedSourceData[packageName] ||
|
||||||
|
!excludedSourceData[packageName].excludedDocumentTypes.includes(type);
|
||||||
|
const sourceLabel = game.modules.get(packageName)?.title ?? game.system.title;
|
||||||
|
if (!acc[type]) acc[type] = { label: game.i18n.localize(`DOCUMENT.${type}s`), sources: {} };
|
||||||
|
if (!acc[type].sources[packageName])
|
||||||
|
acc[type].sources[packageName] = { label: sourceLabel, checked: sourceChecked, packs: [] };
|
||||||
|
|
||||||
|
const checked = !excludedPackData[id] || !excludedPackData[id].excludedDocumentTypes.includes(type);
|
||||||
|
|
||||||
|
acc[type].sources[packageName].packs.push({
|
||||||
|
pack: id,
|
||||||
|
type,
|
||||||
|
label: id === game.system.id ? game.system.title : game.i18n.localize(label),
|
||||||
|
checked: checked
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static #toggleSource(event, button) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const { type, source } = button.dataset;
|
||||||
|
const currentlyExcluded = this.browserSettings.excludedSources[source]
|
||||||
|
? this.browserSettings.excludedSources[source].excludedDocumentTypes.includes(type)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
if (!this.browserSettings.excludedSources[source])
|
||||||
|
this.browserSettings.excludedSources[source] = { excludedDocumentTypes: [] };
|
||||||
|
this.browserSettings.excludedSources[source].excludedDocumentTypes = currentlyExcluded
|
||||||
|
? this.browserSettings.excludedSources[source].excludedDocumentTypes.filter(x => x !== type)
|
||||||
|
: [...(this.browserSettings.excludedSources[source]?.excludedDocumentTypes ?? []), type];
|
||||||
|
|
||||||
|
const toggleIcon = button.querySelector('a > i');
|
||||||
|
toggleIcon.classList.toggle('fa-toggle-off');
|
||||||
|
toggleIcon.classList.toggle('fa-toggle-on');
|
||||||
|
button.closest('.source-container').querySelector('.checks-container').classList.toggle('collapsed');
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleTypedPack(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const { type, pack } = event.target.dataset;
|
||||||
|
const currentlyExcluded = this.browserSettings.excludedPacks[pack]
|
||||||
|
? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.includes(type)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
if (!this.browserSettings.excludedPacks[pack])
|
||||||
|
this.browserSettings.excludedPacks[pack] = { excludedDocumentTypes: [] };
|
||||||
|
this.browserSettings.excludedPacks[pack].excludedDocumentTypes = currentlyExcluded
|
||||||
|
? this.browserSettings.excludedPacks[pack].excludedDocumentTypes.filter(x => x !== type)
|
||||||
|
: [...(this.browserSettings.excludedPacks[pack]?.excludedDocumentTypes ?? []), type];
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #finish() {
|
||||||
|
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings);
|
||||||
|
await settings.updateSource(this.browserSettings);
|
||||||
|
await game.settings.set(
|
||||||
|
CONFIG.DH.id,
|
||||||
|
CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings,
|
||||||
|
settings.toObject()
|
||||||
|
);
|
||||||
|
|
||||||
|
this.updated = true;
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async configure() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const app = new this();
|
||||||
|
app.addEventListener('close', () => resolve(app.updated), { once: true });
|
||||||
|
app.render({ force: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,3 +16,4 @@ export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
|
||||||
export { default as GroupRollDialog } from './group-roll-dialog.mjs';
|
export { default as GroupRollDialog } from './group-roll-dialog.mjs';
|
||||||
export { default as TagTeamDialog } from './tagTeamDialog.mjs';
|
export { default as TagTeamDialog } from './tagTeamDialog.mjs';
|
||||||
export { default as RiskItAllDialog } from './riskItAllDialog.mjs';
|
export { default as RiskItAllDialog } from './riskItAllDialog.mjs';
|
||||||
|
export { default as CompendiumBrowserSettingsDialog } from './CompendiumBrowserSettings.mjs';
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,11 @@ export default class AttributionDialog extends HandlebarsApplicationMixin(Applic
|
||||||
const after = label.slice(matchIndex + search.length, label.length);
|
const after = label.slice(matchIndex + search.length, label.length);
|
||||||
|
|
||||||
const element = document.createElement('li');
|
const element = document.createElement('li');
|
||||||
element.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
element.innerHTML =
|
||||||
|
`${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`.replaceAll(
|
||||||
|
' ',
|
||||||
|
' '
|
||||||
|
);
|
||||||
if (item.hint) {
|
if (item.hint) {
|
||||||
element.dataset.tooltip = game.i18n.localize(item.hint);
|
element.dataset.tooltip = game.i18n.localize(item.hint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
}
|
}
|
||||||
if (rest.hasOwnProperty('trait')) {
|
if (rest.hasOwnProperty('trait')) {
|
||||||
this.config.roll.trait = rest.trait;
|
this.config.roll.trait = rest.trait;
|
||||||
|
if (!this.config.source.item)
|
||||||
this.config.title = game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
this.config.title = game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||||
ability: game.i18n.localize(abilities[this.config.roll.trait]?.label)
|
ability: game.i18n.localize(abilities[this.config.roll.trait]?.label)
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,11 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
||||||
element.appendChild(img);
|
element.appendChild(img);
|
||||||
|
|
||||||
const label = document.createElement('span');
|
const label = document.createElement('span');
|
||||||
label.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
label.innerHTML =
|
||||||
|
`${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`.replaceAll(
|
||||||
|
' ',
|
||||||
|
' '
|
||||||
|
);
|
||||||
element.appendChild(label);
|
element.appendChild(label);
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
|
@ -119,7 +123,11 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
|
||||||
element.appendChild(img);
|
element.appendChild(img);
|
||||||
|
|
||||||
const label = document.createElement('span');
|
const label = document.createElement('span');
|
||||||
label.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
label.innerHTML =
|
||||||
|
`${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`.replaceAll(
|
||||||
|
' ',
|
||||||
|
' '
|
||||||
|
);
|
||||||
element.appendChild(label);
|
element.appendChild(label);
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,12 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
? { id: this.selected.adversaryType, ...this.settings.adversaryTypes[this.selected.adversaryType] }
|
? { id: this.selected.adversaryType, ...this.settings.adversaryTypes[this.selected.adversaryType] }
|
||||||
: null;
|
: null;
|
||||||
break;
|
break;
|
||||||
|
case 'downtime':
|
||||||
|
context.restOptions = {
|
||||||
|
shortRest: CONFIG.DH.GENERAL.defaultRestOptions.shortRest(),
|
||||||
|
longRest: CONFIG.DH.GENERAL.defaultRestOptions.longRest()
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
@ -225,6 +231,15 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
}
|
}
|
||||||
|
|
||||||
static async removeItem(_, target) {
|
static async removeItem(_, target) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize(`DAGGERHEART.SETTINGS.Homebrew.deleteItemTitle`)
|
||||||
|
},
|
||||||
|
content: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.deleteItemText')
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
const { type, id } = target.dataset;
|
const { type, id } = target.dataset;
|
||||||
const isDowntime = ['shortRest', 'longRest'].includes(type);
|
const isDowntime = ['shortRest', 'longRest'].includes(type);
|
||||||
const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`;
|
const path = isDowntime ? `restMoves.${type}.moves` : `itemFeatures.${type}`;
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,55 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
super(options);
|
super(options);
|
||||||
|
|
||||||
const ignoredActorKeys = ['config', 'DhEnvironment'];
|
const ignoredActorKeys = ['config', 'DhEnvironment', 'DhParty'];
|
||||||
this.changeChoices = Object.keys(game.system.api.models.actors).reduce((acc, key) => {
|
|
||||||
if (!ignoredActorKeys.includes(key)) {
|
const getAllLeaves = (root, group, parentPath = '') => {
|
||||||
const model = game.system.api.models.actors[key];
|
const leaves = [];
|
||||||
const attributes = CONFIG.Token.documentClass.getTrackedAttributes(model);
|
const rootKey = `${parentPath ? `${parentPath}.` : ''}${root.name}`;
|
||||||
// As per DHToken._getTrackedAttributesFromSchema, attributes.bar have a max version as well.
|
for (const field of Object.values(root.fields)) {
|
||||||
const maxAttributes = attributes.bar.map(x => [...x, 'max']);
|
if (field instanceof foundry.data.fields.SchemaField)
|
||||||
attributes.value.push(...maxAttributes);
|
leaves.push(...getAllLeaves(field, group, rootKey));
|
||||||
const group = game.i18n.localize(model.metadata.label);
|
else
|
||||||
const choices = CONFIG.Token.documentClass
|
leaves.push({
|
||||||
.getTrackedAttributeChoices(attributes, model)
|
value: `${rootKey}.${field.name}`,
|
||||||
.map(x => ({ ...x, group: group }));
|
label: game.i18n.localize(field.label),
|
||||||
acc.push(...choices);
|
hint: game.i18n.localize(field.hint),
|
||||||
|
group
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return leaves;
|
||||||
|
};
|
||||||
|
this.changeChoices = Object.keys(game.system.api.models.actors).reduce((acc, key) => {
|
||||||
|
if (ignoredActorKeys.includes(key)) return acc;
|
||||||
|
|
||||||
|
const model = game.system.api.models.actors[key];
|
||||||
|
const group = game.i18n.localize(model.metadata.label);
|
||||||
|
const attributes = CONFIG.Token.documentClass.getTrackedAttributes(model.metadata.type);
|
||||||
|
|
||||||
|
const getLabel = path => {
|
||||||
|
const label = model.schema.getField(path)?.label;
|
||||||
|
return label ? game.i18n.localize(label) : path;
|
||||||
|
};
|
||||||
|
|
||||||
|
const bars = attributes.bar.flatMap(x => {
|
||||||
|
const joined = `${x.join('.')}.max`;
|
||||||
|
const label =
|
||||||
|
joined === 'resources.hope.max'
|
||||||
|
? 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxHope.label'
|
||||||
|
: getLabel(joined);
|
||||||
|
return { value: joined, label, group };
|
||||||
|
});
|
||||||
|
const values = attributes.value.flatMap(x => {
|
||||||
|
const joined = x.join('.');
|
||||||
|
return { value: joined, label: getLabel(joined), group };
|
||||||
|
});
|
||||||
|
|
||||||
|
const bonuses = getAllLeaves(model.schema.fields.bonuses, group);
|
||||||
|
const rules = getAllLeaves(model.schema.fields.rules, group);
|
||||||
|
|
||||||
|
acc.push(...bars, ...values, ...rules, ...bonuses);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
@ -68,14 +103,18 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
|
||||||
},
|
},
|
||||||
render: function (item, search) {
|
render: function (item, search) {
|
||||||
const label = game.i18n.localize(item.label);
|
const label = game.i18n.localize(item.label);
|
||||||
const matchIndex = label.toLowerCase().indexOf(search);
|
const matchIndex = label.toLowerCase().indexOf(search.toLowerCase());
|
||||||
|
|
||||||
const beforeText = label.slice(0, matchIndex);
|
const beforeText = label.slice(0, matchIndex);
|
||||||
const matchText = label.slice(matchIndex, matchIndex + search.length);
|
const matchText = label.slice(matchIndex, matchIndex + search.length);
|
||||||
const after = label.slice(matchIndex + search.length, label.length);
|
const after = label.slice(matchIndex + search.length, label.length);
|
||||||
|
|
||||||
const element = document.createElement('li');
|
const element = document.createElement('li');
|
||||||
element.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
element.innerHTML =
|
||||||
|
`${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`.replaceAll(
|
||||||
|
' ',
|
||||||
|
' '
|
||||||
|
);
|
||||||
if (item.hint) {
|
if (item.hint) {
|
||||||
element.dataset.tooltip = game.i18n.localize(item.hint);
|
element.dataset.tooltip = game.i18n.localize(item.hint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,11 @@ export default class SettingActiveEffectConfig extends HandlebarsApplicationMixi
|
||||||
const after = label.slice(matchIndex + search.length, label.length);
|
const after = label.slice(matchIndex + search.length, label.length);
|
||||||
|
|
||||||
const element = document.createElement('li');
|
const element = document.createElement('li');
|
||||||
element.innerHTML = `${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`;
|
element.innerHTML =
|
||||||
|
`${beforeText}${matchText ? `<strong>${matchText}</strong>` : ''}${after}`.replaceAll(
|
||||||
|
' ',
|
||||||
|
' '
|
||||||
|
);
|
||||||
if (item.hint) {
|
if (item.hint) {
|
||||||
element.dataset.tooltip = game.i18n.localize(item.hint);
|
element.dataset.tooltip = game.i18n.localize(item.hint);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
icon: 'fa-solid fa-lightbulb',
|
icon: 'fa-solid fa-lightbulb',
|
||||||
condition: target => {
|
condition: target => {
|
||||||
const doc = getDocFromElementSync(target);
|
const doc = getDocFromElementSync(target);
|
||||||
return doc && !doc.disabled;
|
return doc && !doc.disabled && doc.type !== 'beastform';
|
||||||
},
|
},
|
||||||
callback: async target => (await getDocFromElement(target)).update({ disabled: true })
|
callback: async target => (await getDocFromElement(target)).update({ disabled: true })
|
||||||
},
|
},
|
||||||
|
|
@ -442,7 +442,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
icon: 'fa-regular fa-lightbulb',
|
icon: 'fa-regular fa-lightbulb',
|
||||||
condition: target => {
|
condition: target => {
|
||||||
const doc = getDocFromElementSync(target);
|
const doc = getDocFromElementSync(target);
|
||||||
return doc && doc.disabled;
|
return doc && doc.disabled && doc.type !== 'beastform';
|
||||||
},
|
},
|
||||||
callback: async target => (await getDocFromElement(target)).update({ disabled: false })
|
callback: async target => (await getDocFromElement(target)).update({ disabled: false })
|
||||||
}
|
}
|
||||||
|
|
@ -536,6 +536,10 @@ export default function DHApplicationMixin(Base) {
|
||||||
options.push({
|
options.push({
|
||||||
name: 'CONTROLS.CommonDelete',
|
name: 'CONTROLS.CommonDelete',
|
||||||
icon: 'fa-solid fa-trash',
|
icon: 'fa-solid fa-trash',
|
||||||
|
condition: target => {
|
||||||
|
const doc = getDocFromElementSync(target);
|
||||||
|
return doc && doc.type !== 'beastform';
|
||||||
|
},
|
||||||
callback: async (target, event) => {
|
callback: async (target, event) => {
|
||||||
const doc = await getDocFromElement(target);
|
const doc = await getDocFromElement(target);
|
||||||
if (event.shiftKey) return doc.delete();
|
if (event.shiftKey) return doc.delete();
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
export default function ItemAttachmentSheet(Base) {
|
export default function ItemAttachmentSheet(Base) {
|
||||||
return class extends Base {
|
return class extends Base {
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
...super.DEFAULT_OPTIONS,
|
|
||||||
dragDrop: [
|
dragDrop: [
|
||||||
...(super.DEFAULT_OPTIONS.dragDrop || []),
|
...(super.DEFAULT_OPTIONS.dragDrop || []),
|
||||||
{ dragSelector: null, dropSelector: '.attachments-section' }
|
{ dragSelector: null, dropSelector: '.attachments-section' }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,6 +19,15 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig;
|
this.config = CONFIG.DH.ITEMBROWSER.compendiumConfig;
|
||||||
this.presets = {};
|
this.presets = {};
|
||||||
this.compendiumBrowserTypeKey = 'compendiumBrowserDefault';
|
this.compendiumBrowserTypeKey = 'compendiumBrowserDefault';
|
||||||
|
|
||||||
|
this.setupHooks = Hooks.on(socketEvent.Refresh, ({ refreshType }) => {
|
||||||
|
if (refreshType === RefreshType.CompendiumBrowser) {
|
||||||
|
if (this.rendered) {
|
||||||
|
this.render();
|
||||||
|
this.loadItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -35,7 +46,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
selectFolder: this.selectFolder,
|
selectFolder: this.selectFolder,
|
||||||
expandContent: this.expandContent,
|
expandContent: this.expandContent,
|
||||||
resetFilters: this.resetFilters,
|
resetFilters: this.resetFilters,
|
||||||
sortList: this.sortList
|
sortList: this.sortList,
|
||||||
|
openSettings: this.openSettings
|
||||||
},
|
},
|
||||||
position: {
|
position: {
|
||||||
left: 100,
|
left: 100,
|
||||||
|
|
@ -157,6 +169,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
context.formatChoices = this.formatChoices;
|
context.formatChoices = this.formatChoices;
|
||||||
context.items = this.items;
|
context.items = this.items;
|
||||||
context.presets = this.presets;
|
context.presets = this.presets;
|
||||||
|
context.isGM = game.user.isGM;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,6 +228,10 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
loadItems() {
|
loadItems() {
|
||||||
let loadTimeout = this.toggleLoader(true);
|
let loadTimeout = this.toggleLoader(true);
|
||||||
|
|
||||||
|
const browserSettings = game.settings.get(
|
||||||
|
CONFIG.DH.id,
|
||||||
|
CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings
|
||||||
|
);
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
game.packs.forEach(pack => {
|
game.packs.forEach(pack => {
|
||||||
|
|
@ -227,7 +245,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
|
||||||
Promise.all(promises).then(async result => {
|
Promise.all(promises).then(async result => {
|
||||||
this.items = ItemBrowser.sortBy(
|
this.items = ItemBrowser.sortBy(
|
||||||
result.flatMap(r => r),
|
result.flatMap(r => r).filter(r => !browserSettings.isEntryExcluded.bind(browserSettings)(r)),
|
||||||
'name'
|
'name'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -512,6 +530,22 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
itemListContainer.replaceChildren(...newOrder);
|
itemListContainer.replaceChildren(...newOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async openSettings() {
|
||||||
|
const settingsUpdated = await game.system.api.applications.dialogs.CompendiumBrowserSettingsDialog.configure();
|
||||||
|
if (settingsUpdated) {
|
||||||
|
if (this.rendered) {
|
||||||
|
this.render();
|
||||||
|
this.loadItems();
|
||||||
|
}
|
||||||
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
||||||
|
action: socketEvent.Refresh,
|
||||||
|
data: {
|
||||||
|
refreshType: RefreshType.CompendiumBrowser
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_createDragProcess() {
|
_createDragProcess() {
|
||||||
new foundry.applications.ux.DragDrop.implementation({
|
new foundry.applications.ux.DragDrop.implementation({
|
||||||
dragSelector: '.item-container',
|
dragSelector: '.item-container',
|
||||||
|
|
@ -571,4 +605,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
headerActions.append(button);
|
headerActions.append(button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async close(options = {}) {
|
||||||
|
Hooks.off(socketEvent.Refresh, this.setupHooks);
|
||||||
|
await super.close(options);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import DhMeasuredTemplate from "./measuredTemplate.mjs";
|
import DhMeasuredTemplate from './measuredTemplate.mjs';
|
||||||
|
|
||||||
export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
|
|
@ -63,7 +63,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
||||||
const originRadius = (this.bounds.width * boundsCorrection) / 2;
|
const originRadius = (this.bounds.width * boundsCorrection) / 2;
|
||||||
const targetRadius = (target.bounds.width * boundsCorrection) / 2;
|
const targetRadius = (target.bounds.width * boundsCorrection) / 2;
|
||||||
const distance = canvas.grid.measurePath([originPoint, destinationPoint]).distance;
|
const distance = canvas.grid.measurePath([originPoint, destinationPoint]).distance;
|
||||||
return distance - originRadius - targetRadius + canvas.grid.distance;
|
return Math.floor(distance - originRadius - targetRadius + canvas.grid.distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute what the closest grid space of each token is, then compute that distance
|
// Compute what the closest grid space of each token is, then compute that distance
|
||||||
|
|
@ -85,7 +85,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token {
|
||||||
|
|
||||||
// Check if the setting is enabled
|
// Check if the setting is enabled
|
||||||
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).showTokenDistance;
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).showTokenDistance;
|
||||||
if (setting === "never" || (setting === "encounters" && !game.combat?.started)) return;
|
if (setting === 'never' || (setting === 'encounters' && !game.combat?.started)) return;
|
||||||
|
|
||||||
// Check if this token isn't invisible and is actually being hovered
|
// Check if this token isn't invisible and is actually being hovered
|
||||||
const isTokenValid =
|
const isTokenValid =
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
target: {
|
target: {
|
||||||
|
amount: 1,
|
||||||
type: 'friendly'
|
type: 'friendly'
|
||||||
},
|
},
|
||||||
damage: {
|
damage: {
|
||||||
|
|
@ -304,6 +305,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
target: {
|
target: {
|
||||||
|
amount: 1,
|
||||||
type: 'friendly'
|
type: 'friendly'
|
||||||
},
|
},
|
||||||
damage: {
|
damage: {
|
||||||
|
|
@ -329,7 +331,56 @@ export const defaultRestOptions = {
|
||||||
icon: 'fa-solid fa-dumbbell',
|
icon: 'fa-solid fa-dumbbell',
|
||||||
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.description'),
|
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.description'),
|
||||||
actions: {},
|
actions: {
|
||||||
|
prepare: {
|
||||||
|
type: 'healing',
|
||||||
|
systemPath: 'restMoves.shortRest.moves.prepare.actions',
|
||||||
|
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.name'),
|
||||||
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
|
actionType: 'action',
|
||||||
|
chatDisplay: false,
|
||||||
|
target: {
|
||||||
|
type: 'self'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
applyTo: healingTypes.hope.id,
|
||||||
|
value: {
|
||||||
|
custom: {
|
||||||
|
enabled: true,
|
||||||
|
formula: '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prepareWithFriends: {
|
||||||
|
type: 'healing',
|
||||||
|
systemPath: 'restMoves.shortRest.moves.prepare.actions',
|
||||||
|
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepareWithFriends.name'),
|
||||||
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
|
actionType: 'action',
|
||||||
|
chatDisplay: false,
|
||||||
|
target: {
|
||||||
|
type: 'self'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
applyTo: healingTypes.hope.id,
|
||||||
|
value: {
|
||||||
|
custom: {
|
||||||
|
enabled: true,
|
||||||
|
formula: '2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
effects: []
|
effects: []
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
@ -349,6 +400,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
target: {
|
target: {
|
||||||
|
amount: 1,
|
||||||
type: 'friendly'
|
type: 'friendly'
|
||||||
},
|
},
|
||||||
damage: {
|
damage: {
|
||||||
|
|
@ -417,6 +469,7 @@ export const defaultRestOptions = {
|
||||||
actionType: 'action',
|
actionType: 'action',
|
||||||
chatDisplay: false,
|
chatDisplay: false,
|
||||||
target: {
|
target: {
|
||||||
|
amount: 1,
|
||||||
type: 'friendly'
|
type: 'friendly'
|
||||||
},
|
},
|
||||||
damage: {
|
damage: {
|
||||||
|
|
@ -442,7 +495,56 @@ export const defaultRestOptions = {
|
||||||
icon: 'fa-solid fa-dumbbell',
|
icon: 'fa-solid fa-dumbbell',
|
||||||
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.description'),
|
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.description'),
|
||||||
actions: {},
|
actions: {
|
||||||
|
prepare: {
|
||||||
|
type: 'healing',
|
||||||
|
systemPath: 'restMoves.longRest.moves.prepare.actions',
|
||||||
|
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.name'),
|
||||||
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
|
actionType: 'action',
|
||||||
|
chatDisplay: false,
|
||||||
|
target: {
|
||||||
|
type: 'self'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
applyTo: healingTypes.hope.id,
|
||||||
|
value: {
|
||||||
|
custom: {
|
||||||
|
enabled: true,
|
||||||
|
formula: '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
prepareWithFriends: {
|
||||||
|
type: 'healing',
|
||||||
|
systemPath: 'restMoves.longRest.moves.prepare.actions',
|
||||||
|
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepareWithFriends.name'),
|
||||||
|
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||||
|
actionType: 'action',
|
||||||
|
chatDisplay: false,
|
||||||
|
target: {
|
||||||
|
type: 'self'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
parts: [
|
||||||
|
{
|
||||||
|
applyTo: healingTypes.hope.id,
|
||||||
|
value: {
|
||||||
|
custom: {
|
||||||
|
enabled: true,
|
||||||
|
formula: '2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
effects: []
|
effects: []
|
||||||
},
|
},
|
||||||
workOnAProject: {
|
workOnAProject: {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export const gameSettings = {
|
||||||
LastMigrationVersion: 'LastMigrationVersion',
|
LastMigrationVersion: 'LastMigrationVersion',
|
||||||
TagTeamRoll: 'TagTeamRoll',
|
TagTeamRoll: 'TagTeamRoll',
|
||||||
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
SpotlightRequestQueue: 'SpotlightRequestQueue',
|
||||||
|
CompendiumBrowserSettings: 'CompendiumBrowserSettings'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const actionAutomationChoices = {
|
export const actionAutomationChoices = {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ export { default as DhCombatant } from './combatant.mjs';
|
||||||
export { default as DhTagTeamRoll } from './tagTeamRoll.mjs';
|
export { default as DhTagTeamRoll } from './tagTeamRoll.mjs';
|
||||||
export { default as DhRollTable } from './rollTable.mjs';
|
export { default as DhRollTable } from './rollTable.mjs';
|
||||||
export { default as RegisteredTriggers } from './registeredTriggers.mjs';
|
export { default as RegisteredTriggers } from './registeredTriggers.mjs';
|
||||||
|
export { default as CompendiumBrowserSettings } from './compendiumBrowserSettings.mjs';
|
||||||
|
|
||||||
export * as countdowns from './countdowns.mjs';
|
export * as countdowns from './countdowns.mjs';
|
||||||
export * as actions from './action/_module.mjs';
|
export * as actions from './action/_module.mjs';
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
|
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
||||||
|
|
||||||
if (this.chatDisplay) await this.toChat();
|
if (this.chatDisplay && !config.actionChatMessageHandled) await this.toChat();
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
@ -240,9 +240,13 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
prepareBaseConfig(event) {
|
prepareBaseConfig(event) {
|
||||||
|
const isActor = this.item instanceof CONFIG.Actor.documentClass;
|
||||||
|
const actionTitle = game.i18n.localize(this.name);
|
||||||
|
const itemTitle = isActor || this.item.name === actionTitle ? '' : `${this.item.name} - `;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
event,
|
event,
|
||||||
title: `${this.item instanceof CONFIG.Actor.documentClass ? '' : `${this.item.name}: `}${game.i18n.localize(this.name)}`,
|
title: `${itemTitle}${actionTitle}`,
|
||||||
source: {
|
source: {
|
||||||
item: this.item._id,
|
item: this.item._id,
|
||||||
originItem: this.originItem,
|
originItem: this.originItem,
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,14 @@ export default class DhpAdversary extends BaseDataActor {
|
||||||
integer: true,
|
integer: true,
|
||||||
label: 'DAGGERHEART.GENERAL.hordeHp'
|
label: 'DAGGERHEART.GENERAL.hordeHp'
|
||||||
}),
|
}),
|
||||||
criticalThreshold: new fields.NumberField({ required: true, integer: true, min: 1, max: 20, initial: 20 }),
|
criticalThreshold: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
integer: true,
|
||||||
|
min: 1,
|
||||||
|
max: 20,
|
||||||
|
initial: 20,
|
||||||
|
label: 'DAGGERHEART.ACTIONS.Settings.criticalThreshold'
|
||||||
|
}),
|
||||||
damageThresholds: new fields.SchemaField({
|
damageThresholds: new fields.SchemaField({
|
||||||
major: new fields.NumberField({
|
major: new fields.NumberField({
|
||||||
required: true,
|
required: true,
|
||||||
|
|
|
||||||
|
|
@ -29,17 +29,40 @@ const resistanceField = (resistanceLabel, immunityLabel, reductionLabel) =>
|
||||||
/* Common rules applying to Characters and Adversaries */
|
/* Common rules applying to Characters and Adversaries */
|
||||||
export const commonActorRules = (extendedData = { damageReduction: {}, attack: { damage: {} } }) => ({
|
export const commonActorRules = (extendedData = { damageReduction: {}, attack: { damage: {} } }) => ({
|
||||||
conditionImmunities: new fields.SchemaField({
|
conditionImmunities: new fields.SchemaField({
|
||||||
hidden: new fields.BooleanField({ initial: false }),
|
hidden: new fields.BooleanField({
|
||||||
restrained: new fields.BooleanField({ initial: false }),
|
initial: false,
|
||||||
vulnerable: new fields.BooleanField({ initial: false })
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.hidden'
|
||||||
|
}),
|
||||||
|
restrained: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.restrained'
|
||||||
|
}),
|
||||||
|
vulnerable: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable'
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
damageReduction: new fields.SchemaField({
|
damageReduction: new fields.SchemaField({
|
||||||
thresholdImmunities: new fields.SchemaField({
|
thresholdImmunities: new fields.SchemaField({
|
||||||
minor: new fields.BooleanField({ initial: false })
|
minor: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.thresholdImmunities.minor.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.thresholdImmunities.minor.hint'
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
reduceSeverity: new fields.SchemaField({
|
reduceSeverity: new fields.SchemaField({
|
||||||
magical: new fields.NumberField({ initial: 0, min: 0 }),
|
magical: new fields.NumberField({
|
||||||
physical: new fields.NumberField({ initial: 0, min: 0 })
|
initial: 0,
|
||||||
|
min: 0,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.magical.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.magical.hint'
|
||||||
|
}),
|
||||||
|
physical: new fields.NumberField({
|
||||||
|
initial: 0,
|
||||||
|
min: 0,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.physical.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.reduceSeverity.physical.hint'
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
...(extendedData.damageReduction ?? {})
|
...(extendedData.damageReduction ?? {})
|
||||||
}),
|
}),
|
||||||
|
|
@ -49,12 +72,16 @@ export const commonActorRules = (extendedData = { damageReduction: {}, attack: {
|
||||||
hpDamageMultiplier: new fields.NumberField({
|
hpDamageMultiplier: new fields.NumberField({
|
||||||
required: true,
|
required: true,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
initial: 1
|
initial: 1,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Attack.hpDamageMultiplier.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Attack.hpDamageMultiplier.hint'
|
||||||
}),
|
}),
|
||||||
hpDamageTakenMultiplier: new fields.NumberField({
|
hpDamageTakenMultiplier: new fields.NumberField({
|
||||||
required: true,
|
required: true,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
initial: 1
|
initial: 1,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Attack.hpDamageTakenMultiplier.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Attack.hpDamageTakenMultiplier.hint'
|
||||||
}),
|
}),
|
||||||
...(extendedData.attack?.damage ?? {})
|
...(extendedData.attack?.damage ?? {})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
||||||
),
|
),
|
||||||
stress: resourceField(6, 0, 'DAGGERHEART.GENERAL.stress', true),
|
stress: resourceField(6, 0, 'DAGGERHEART.GENERAL.stress', true),
|
||||||
hope: new fields.SchemaField({
|
hope: new fields.SchemaField(
|
||||||
|
{
|
||||||
value: new fields.NumberField({
|
value: new fields.NumberField({
|
||||||
initial: 2,
|
initial: 2,
|
||||||
min: 0,
|
min: 0,
|
||||||
|
|
@ -43,7 +44,9 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
label: 'DAGGERHEART.GENERAL.hope'
|
label: 'DAGGERHEART.GENERAL.hope'
|
||||||
}),
|
}),
|
||||||
isReversed: new fields.BooleanField({ initial: false })
|
isReversed: new fields.BooleanField({ initial: false })
|
||||||
})
|
},
|
||||||
|
{ label: 'DAGGERHEART.GENERAL.hope' }
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
traits: new fields.SchemaField({
|
traits: new fields.SchemaField({
|
||||||
agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'),
|
agility: attributeField('DAGGERHEART.CONFIG.Traits.agility.name'),
|
||||||
|
|
@ -222,8 +225,16 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
rules: new fields.SchemaField({
|
rules: new fields.SchemaField({
|
||||||
...commonActorRules({
|
...commonActorRules({
|
||||||
damageReduction: {
|
damageReduction: {
|
||||||
magical: new fields.BooleanField({ initial: false }),
|
magical: new fields.BooleanField({
|
||||||
physical: new fields.BooleanField({ initial: false }),
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.magical.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.magical.hint'
|
||||||
|
}),
|
||||||
|
physical: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.physical.label',
|
||||||
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.physical.hint'
|
||||||
|
}),
|
||||||
maxArmorMarked: new fields.SchemaField({
|
maxArmorMarked: new fields.SchemaField({
|
||||||
value: new fields.NumberField({
|
value: new fields.NumberField({
|
||||||
required: true,
|
required: true,
|
||||||
|
|
@ -253,7 +264,10 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label',
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.label',
|
||||||
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint'
|
hint: 'DAGGERHEART.GENERAL.Rules.damageReduction.increasePerArmorMark.hint'
|
||||||
}),
|
}),
|
||||||
disabledArmor: new fields.BooleanField({ intial: false })
|
disabledArmor: new fields.BooleanField({
|
||||||
|
intial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.damageReduction.disabledArmor.label'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
attack: {
|
attack: {
|
||||||
damage: {
|
damage: {
|
||||||
|
|
@ -301,12 +315,14 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
label: 'DAGGERHEART.ACTORS.Character.defaultFearDice'
|
label: 'DAGGERHEART.ACTORS.Character.defaultFearDice'
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
runeWard: new fields.BooleanField({ initial: false }),
|
|
||||||
burden: new fields.SchemaField({
|
burden: new fields.SchemaField({
|
||||||
ignore: new fields.BooleanField()
|
ignore: new fields.BooleanField({ label: 'DAGGERHEART.ACTORS.Character.burden.ignore.label' })
|
||||||
}),
|
}),
|
||||||
roll: new fields.SchemaField({
|
roll: new fields.SchemaField({
|
||||||
guaranteedCritical: new fields.BooleanField()
|
guaranteedCritical: new fields.BooleanField({
|
||||||
|
label: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.label',
|
||||||
|
hint: 'DAGGERHEART.ACTORS.Character.roll.guaranteedCritical.hint'
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,18 @@ export default class DhCompanion extends BaseDataActor {
|
||||||
),
|
),
|
||||||
rules: new fields.SchemaField({
|
rules: new fields.SchemaField({
|
||||||
conditionImmunities: new fields.SchemaField({
|
conditionImmunities: new fields.SchemaField({
|
||||||
hidden: new fields.BooleanField({ initial: false }),
|
hidden: new fields.BooleanField({
|
||||||
restrained: new fields.BooleanField({ initial: false }),
|
initial: false,
|
||||||
vulnerable: new fields.BooleanField({ initial: false })
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.hidden'
|
||||||
|
}),
|
||||||
|
restrained: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.restrained'
|
||||||
|
}),
|
||||||
|
vulnerable: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.Rules.conditionImmunities.vulnerable'
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
attack: new ActionField({
|
attack: new ActionField({
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
title: new fields.StringField(),
|
title: new fields.StringField(),
|
||||||
|
actionDescription: new fields.HTMLField(),
|
||||||
roll: new fields.ObjectField(),
|
roll: new fields.ObjectField(),
|
||||||
targets: targetsField(),
|
targets: targetsField(),
|
||||||
hasRoll: new fields.BooleanField({ initial: false }),
|
hasRoll: new fields.BooleanField({ initial: false }),
|
||||||
|
|
|
||||||
35
module/data/compendiumBrowserSettings.mjs
Normal file
35
module/data/compendiumBrowserSettings.mjs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
export default class CompendiumBrowserSettings extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
return {
|
||||||
|
excludedSources: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
excludedDocumentTypes: new fields.ArrayField(
|
||||||
|
new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES })
|
||||||
|
)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
excludedPacks: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
excludedDocumentTypes: new fields.ArrayField(
|
||||||
|
new fields.StringField({ required: true, choices: CONST.SYSTEM_SPECIFIC_COMPENDIUM_TYPES })
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isEntryExcluded(item) {
|
||||||
|
const pack = game.packs.get(item.pack);
|
||||||
|
if (!pack) return false;
|
||||||
|
|
||||||
|
const excludedSourceData = this.excludedSources[pack.metadata.packageName];
|
||||||
|
if (excludedSourceData && excludedSourceData.excludedDocumentTypes.includes(pack.metadata.type)) return true;
|
||||||
|
|
||||||
|
const excludedPackData = this.excludedPacks[item.pack];
|
||||||
|
if (excludedPackData && excludedPackData.excludedDocumentTypes.includes(pack.metadata.type)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -68,6 +68,8 @@ export default class DamageField extends fields.SchemaField {
|
||||||
|
|
||||||
const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig);
|
const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig);
|
||||||
if (!damageResult) return false;
|
if (!damageResult) return false;
|
||||||
|
if (damageResult.actionChatMessageHandled) config.actionChatMessageHandled = true;
|
||||||
|
|
||||||
config.damage = damageResult.damage;
|
config.damage = damageResult.damage;
|
||||||
config.message ??= damageConfig.message;
|
config.message ??= damageConfig.message;
|
||||||
}
|
}
|
||||||
|
|
@ -107,8 +109,8 @@ export default class DamageField extends fields.SchemaField {
|
||||||
);
|
);
|
||||||
else {
|
else {
|
||||||
const configDamage = foundry.utils.deepClone(config.damage);
|
const configDamage = foundry.utils.deepClone(config.damage);
|
||||||
const hpDamageMultiplier = config.actionActor?.system.rules.attack.damage.hpDamageMultiplier ?? 1;
|
const hpDamageMultiplier = config.actionActor?.system.rules?.attack?.damage?.hpDamageMultiplier ?? 1;
|
||||||
const hpDamageTakenMultiplier = actor.system.rules.attack.damage.hpDamageTakenMultiplier;
|
const hpDamageTakenMultiplier = actor.system.rules?.attack?.damage?.hpDamageTakenMultiplier;
|
||||||
if (configDamage.hitPoints) {
|
if (configDamage.hitPoints) {
|
||||||
for (const part of configDamage.hitPoints.parts) {
|
for (const part of configDamage.hitPoints.parts) {
|
||||||
part.total = Math.ceil(part.total * hpDamageMultiplier * hpDamageTakenMultiplier);
|
part.total = Math.ceil(part.total * hpDamageMultiplier * hpDamageTakenMultiplier);
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,20 @@ const attributeField = label =>
|
||||||
});
|
});
|
||||||
|
|
||||||
const resourceField = (max = 0, initial = 0, label, reverse = false, maxLabel) =>
|
const resourceField = (max = 0, initial = 0, label, reverse = false, maxLabel) =>
|
||||||
new fields.SchemaField({
|
new fields.SchemaField(
|
||||||
|
{
|
||||||
value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }),
|
value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }),
|
||||||
max: new fields.NumberField({
|
max: new fields.NumberField({
|
||||||
initial: max,
|
initial: max,
|
||||||
integer: true,
|
integer: true,
|
||||||
label:
|
label:
|
||||||
maxLabel ?? game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
|
maxLabel ??
|
||||||
|
game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
|
||||||
}),
|
}),
|
||||||
isReversed: new fields.BooleanField({ initial: reverse })
|
isReversed: new fields.BooleanField({ initial: reverse })
|
||||||
});
|
},
|
||||||
|
{ label }
|
||||||
|
);
|
||||||
|
|
||||||
const stressDamageReductionRule = localizationPath =>
|
const stressDamageReductionRule = localizationPath =>
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
|
|
|
||||||
|
|
@ -253,4 +253,20 @@ export default class DHBeastform extends BaseDataItem {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onCreate(_data, _options, userId) {
|
||||||
|
if (!this.actor && game.user.id === userId) {
|
||||||
|
const hasBeastformEffect = this.parent.effects.some(x => x.type === 'beastform');
|
||||||
|
if (!hasBeastformEffect)
|
||||||
|
this.parent.createEmbeddedDocuments('ActiveEffect', [
|
||||||
|
{
|
||||||
|
type: 'beastform',
|
||||||
|
name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'),
|
||||||
|
img: 'icons/creatures/abilities/paw-print-pair-purple.webp'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,12 @@ export default class DhLevelData extends foundry.abstract.DataModel {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
level: new fields.SchemaField({
|
level: new fields.SchemaField({
|
||||||
current: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
current: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
integer: true,
|
||||||
|
initial: 1,
|
||||||
|
label: 'DAGGERHEART.GENERAL.currentLevel'
|
||||||
|
}),
|
||||||
changed: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
changed: new fields.NumberField({ required: true, integer: true, initial: 1 }),
|
||||||
bonuses: new fields.TypedObjectField(new fields.NumberField({ integer: true, nullable: false }))
|
bonuses: new fields.TypedObjectField(new fields.NumberField({ integer: true, nullable: false }))
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
extendEnvironmentDescriptions: new BooleanField(),
|
extendEnvironmentDescriptions: new BooleanField(),
|
||||||
extendItemDescriptions: new BooleanField(),
|
extendItemDescriptions: new BooleanField(),
|
||||||
expandRollMessage: new SchemaField({
|
expandRollMessage: new SchemaField({
|
||||||
desc: new BooleanField(),
|
desc: new BooleanField({ initial: true }),
|
||||||
roll: new BooleanField(),
|
roll: new BooleanField(),
|
||||||
damage: new BooleanField(),
|
damage: new BooleanField(),
|
||||||
target: new BooleanField()
|
target: new BooleanField()
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,19 @@ export default class DHRoll extends Roll {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async toMessage(roll, config) {
|
static async toMessage(roll, config) {
|
||||||
|
const item = config.data.parent?.items?.get?.(config.source.item) ?? null;
|
||||||
|
const action = item ? item.system.actions.get(config.source.action) : null;
|
||||||
|
let actionDescription = null;
|
||||||
|
if (action?.chatDisplay) {
|
||||||
|
actionDescription = action
|
||||||
|
? await foundry.applications.ux.TextEditor.implementation.enrichHTML(action.description, {
|
||||||
|
relativeTo: config.data,
|
||||||
|
rollData: config.data.getRollData?.() ?? {}
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
config.actionChatMessageHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
const cls = getDocumentClass('ChatMessage'),
|
const cls = getDocumentClass('ChatMessage'),
|
||||||
msgData = {
|
msgData = {
|
||||||
type: this.messageType,
|
type: this.messageType,
|
||||||
|
|
@ -103,7 +116,7 @@ export default class DHRoll extends Roll {
|
||||||
title: roll.title,
|
title: roll.title,
|
||||||
speaker: cls.getSpeaker({ actor: roll.data?.parent }),
|
speaker: cls.getSpeaker({ actor: roll.data?.parent }),
|
||||||
sound: config.mute ? null : CONFIG.sounds.dice,
|
sound: config.mute ? null : CONFIG.sounds.dice,
|
||||||
system: config,
|
system: { ...config, actionDescription },
|
||||||
rolls: [roll]
|
rolls: [roll]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,14 +61,15 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
update.img = 'icons/magic/life/heart-cross-blue.webp';
|
update.img = 'icons/magic/life/heart-cross-blue.webp';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const statuses = Object.keys(data.statuses ?? {});
|
||||||
const immuneStatuses =
|
const immuneStatuses =
|
||||||
data.statuses?.filter(
|
statuses.filter(
|
||||||
status =>
|
status =>
|
||||||
this.parent.system.rules?.conditionImmunities &&
|
this.parent.system.rules?.conditionImmunities &&
|
||||||
this.parent.system.rules.conditionImmunities[status]
|
this.parent.system.rules.conditionImmunities[status]
|
||||||
) ?? [];
|
) ?? [];
|
||||||
if (immuneStatuses.length > 0) {
|
if (immuneStatuses.length > 0) {
|
||||||
update.statuses = data.statuses.filter(x => !immuneStatuses.includes(x));
|
update.statuses = statuses.filter(x => !immuneStatuses.includes(x));
|
||||||
const conditions = CONFIG.DH.GENERAL.conditions();
|
const conditions = CONFIG.DH.GENERAL.conditions();
|
||||||
const scrollingTexts = immuneStatuses.map(status => ({
|
const scrollingTexts = immuneStatuses.map(status => ({
|
||||||
text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', {
|
text: game.i18n.format('DAGGERHEART.ACTIVEEFFECT.immuneStatusText', {
|
||||||
|
|
@ -113,6 +114,11 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
super.applyField(model, change, field);
|
super.applyField(model, change, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_applyLegacy(actor, change, changes) {
|
||||||
|
change.value = DhActiveEffect.getChangeValue(actor, change, change.effect);
|
||||||
|
super._applyLegacy(actor, change, changes);
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
static getChangeValue(model, change, effect) {
|
static getChangeValue(model, change, effect) {
|
||||||
let value = change.value;
|
let value = change.value;
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
} else if (s.classList.contains('damage-section'))
|
} else if (s.classList.contains('damage-section'))
|
||||||
s.classList.toggle('expanded', autoExpandRoll.damage);
|
s.classList.toggle('expanded', autoExpandRoll.damage);
|
||||||
else if (s.classList.contains('target-section')) s.classList.toggle('expanded', autoExpandRoll.target);
|
else if (s.classList.contains('target-section')) s.classList.toggle('expanded', autoExpandRoll.target);
|
||||||
|
else if (s.classList.contains('description-section'))
|
||||||
|
s.classList.toggle('expanded', autoExpandRoll.desc);
|
||||||
});
|
});
|
||||||
if (itemDesc && autoExpandRoll.desc) itemDesc.setAttribute('open', '');
|
if (itemDesc && autoExpandRoll.desc) itemDesc.setAttribute('open', '');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,78 +1,30 @@
|
||||||
export default class DHToken extends CONFIG.Token.documentClass {
|
export default class DHToken extends CONFIG.Token.documentClass {
|
||||||
/**
|
/**@inheritdoc */
|
||||||
* Inspect the Actor data model and identify the set of attributes which could be used for a Token Bar.
|
static getTrackedAttributeChoices(attributes, typeKey) {
|
||||||
* @param {object} attributes The tracked attributes which can be chosen from
|
|
||||||
* @returns {object} A nested object of attribute choices to display
|
|
||||||
*/
|
|
||||||
static getTrackedAttributeChoices(attributes, model) {
|
|
||||||
attributes = attributes || this.getTrackedAttributes();
|
attributes = attributes || this.getTrackedAttributes();
|
||||||
const barGroup = game.i18n.localize('TOKEN.BarAttributes');
|
const barGroup = game.i18n.localize('TOKEN.BarAttributes');
|
||||||
const valueGroup = game.i18n.localize('TOKEN.BarValues');
|
const valueGroup = game.i18n.localize('TOKEN.BarValues');
|
||||||
|
const actorModel = typeKey ? game.system.api.data.actors[`Dh${typeKey.capitalize()}`] : null;
|
||||||
|
const getLabel = path => {
|
||||||
|
const label = actorModel.schema.getField(path)?.label;
|
||||||
|
return label ? game.i18n.localize(label) : path;
|
||||||
|
};
|
||||||
|
|
||||||
const bars = attributes.bar.map(v => {
|
const bars = attributes.bar.map(v => {
|
||||||
const a = v.join('.');
|
const a = v.join('.');
|
||||||
const modelLabel = model ? game.i18n.localize(model.schema.getField(`${a}.value`).label) : null;
|
return { group: barGroup, value: a, label: getLabel(a) };
|
||||||
return { group: barGroup, value: a, label: modelLabel ? modelLabel : a };
|
|
||||||
});
|
});
|
||||||
bars.sort((a, b) => a.label.compare(b.label));
|
bars.sort((a, b) => a.value.compare(b.value));
|
||||||
|
|
||||||
const invalidAttributes = [
|
const values = attributes.value.map(v => {
|
||||||
'gold',
|
|
||||||
'levelData',
|
|
||||||
'actions',
|
|
||||||
'biography',
|
|
||||||
'class',
|
|
||||||
'multiclass',
|
|
||||||
'companion',
|
|
||||||
'notes',
|
|
||||||
'partner',
|
|
||||||
'description',
|
|
||||||
'impulses',
|
|
||||||
'tier',
|
|
||||||
'type'
|
|
||||||
];
|
|
||||||
const values = attributes.value.reduce((acc, v) => {
|
|
||||||
const a = v.join('.');
|
const a = v.join('.');
|
||||||
if (invalidAttributes.some(x => a.startsWith(x))) return acc;
|
return { group: valueGroup, value: a, label: getLabel(a) };
|
||||||
|
});
|
||||||
const field = model ? model.schema.getField(a) : null;
|
|
||||||
const modelLabel = field ? game.i18n.localize(field.label) : null;
|
|
||||||
const hint = field ? game.i18n.localize(field.hint) : null;
|
|
||||||
acc.push({ group: valueGroup, value: a, label: modelLabel ? modelLabel : a, hint: hint });
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
values.sort((a, b) => a.label.compare(b.label));
|
|
||||||
|
|
||||||
|
values.sort((a, b) => a.value.compare(b.value));
|
||||||
return bars.concat(values);
|
return bars.concat(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _getTrackedAttributesFromSchema(schema, _path = []) {
|
|
||||||
const attributes = { bar: [], value: [] };
|
|
||||||
for (const [name, field] of Object.entries(schema.fields)) {
|
|
||||||
const p = _path.concat([name]);
|
|
||||||
if (field instanceof foundry.data.fields.NumberField) attributes.value.push(p);
|
|
||||||
if (field instanceof foundry.data.fields.BooleanField && field.options.isAttributeChoice)
|
|
||||||
attributes.value.push(p);
|
|
||||||
if (field instanceof foundry.data.fields.StringField) attributes.value.push(p);
|
|
||||||
if (field instanceof foundry.data.fields.ArrayField) attributes.value.push(p);
|
|
||||||
const isSchema = field instanceof foundry.data.fields.SchemaField;
|
|
||||||
const isModel = field instanceof foundry.data.fields.EmbeddedDataField;
|
|
||||||
|
|
||||||
if (isSchema || isModel) {
|
|
||||||
const schema = isModel ? field.model.schema : field;
|
|
||||||
const isBar = schema.has && schema.has('value') && schema.has('max');
|
|
||||||
if (isBar) attributes.bar.push(p);
|
|
||||||
else {
|
|
||||||
const inner = this.getTrackedAttributes(schema, p);
|
|
||||||
attributes.bar.push(...inner.bar);
|
|
||||||
attributes.value.push(...inner.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_shouldRecordMovementHistory() {
|
_shouldRecordMovementHistory() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'systems/daggerheart/templates/dialogs/downtime/activities.hbs',
|
'systems/daggerheart/templates/dialogs/downtime/activities.hbs',
|
||||||
'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs',
|
'systems/daggerheart/templates/dialogs/dice-roll/costSelection.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs',
|
||||||
|
'systems/daggerheart/templates/ui/chat/parts/description-part.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
|
||||||
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
|
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import {
|
||||||
DhHomebrewSettings,
|
DhHomebrewSettings,
|
||||||
DhVariantRuleSettings
|
DhVariantRuleSettings
|
||||||
} from '../applications/settings/_module.mjs';
|
} from '../applications/settings/_module.mjs';
|
||||||
import { DhTagTeamRoll } from '../data/_module.mjs';
|
import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs';
|
||||||
|
|
||||||
export const registerDHSettings = () => {
|
export const registerDHSettings = () => {
|
||||||
registerMenuSettings();
|
registerMenuSettings();
|
||||||
|
|
@ -142,6 +142,12 @@ const registerNonConfigSettings = () => {
|
||||||
config: false,
|
config: false,
|
||||||
type: DhTagTeamRoll
|
type: DhTagTeamRoll
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, {
|
||||||
|
scope: 'client',
|
||||||
|
config: false,
|
||||||
|
type: CompendiumBrowserSettings
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ export const RefreshType = {
|
||||||
Countdown: 'DhCoundownRefresh',
|
Countdown: 'DhCoundownRefresh',
|
||||||
TagTeamRoll: 'DhTagTeamRollRefresh',
|
TagTeamRoll: 'DhTagTeamRollRefresh',
|
||||||
EffectsDisplay: 'DhEffectsDisplayRefresh',
|
EffectsDisplay: 'DhEffectsDisplayRefresh',
|
||||||
Scene: 'DhSceneRefresh'
|
Scene: 'DhSceneRefresh',
|
||||||
|
CompendiumBrowser: 'DhCompendiumBrowserRefresh'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registerSocketHooks = () => {
|
export const registerSocketHooks = () => {
|
||||||
|
|
|
||||||
|
|
@ -388,7 +388,7 @@
|
||||||
"name": "Fumigation",
|
"name": "Fumigation",
|
||||||
"type": "feature",
|
"type": "feature",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Drop a smoke bomb that fi lls the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.</p><p>@Template[type:emanation|range:c]</p>",
|
"description": "<p>Drop a smoke bomb that fills the air within Close range with smoke, Dizzying all targets in this area. Dizzied targets have disadvantage on their next action roll, then clear the condition.</p><p>@Template[type:emanation|range:c]</p>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {
|
"actions": {
|
||||||
"sp7RfJRQJsEUm09m": {
|
"sp7RfJRQJsEUm09m": {
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
"startRound": null,
|
"startRound": null,
|
||||||
"startTurn": null
|
"startTurn": null
|
||||||
},
|
},
|
||||||
"description": "<p class=\"Body-Foundation\">Add your Strength to the presence roll roll.</p>",
|
"description": "<p class=\"Body-Foundation\">Add your Strength to the presence roll.</p>",
|
||||||
"tint": "#ffffff",
|
"tint": "#ffffff",
|
||||||
"statuses": [],
|
"statuses": [],
|
||||||
"sort": 0,
|
"sort": 0,
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,8 @@
|
||||||
"value": 1,
|
"value": 1,
|
||||||
"recovery": "shortRest",
|
"recovery": "shortRest",
|
||||||
"max": "1",
|
"max": "1",
|
||||||
"icon": ""
|
"icon": "",
|
||||||
|
"progression": "decreasing"
|
||||||
},
|
},
|
||||||
"attribution": {
|
"attribution": {
|
||||||
"source": "Daggerheart SRD",
|
"source": "Daggerheart SRD",
|
||||||
|
|
|
||||||
105
styles/less/dialog/compendiumBrowserPackDialog/sheet.less
Normal file
105
styles/less/dialog/compendiumBrowserPackDialog/sheet.less
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
.daggerheart.dialog.dh-style.views.compendium-brower-settings {
|
||||||
|
--text-color: light-dark(@dark-blue, @beige);
|
||||||
|
color: var(--text-color);
|
||||||
|
|
||||||
|
.window-content {
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 440px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.types-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.type-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: var(--font-size-16);
|
||||||
|
font-family: @font-subtitle;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%);
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%);
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sources-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.source-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
.source-inner-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.source-inner-label-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 18px;
|
||||||
|
// color: light-dark(@dark-blue, @golden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checks-container {
|
||||||
|
padding-left: 24px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 4px;
|
||||||
|
transition: height 0.4s ease-in-out;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.collapsed {
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 8px;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
|
|
||||||
.dialog-header-inner {
|
.dialog-header-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
|
@ -45,6 +47,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reaction-chip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: fit-content;
|
||||||
|
gap: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
background: light-dark(@dark-blue-10, @golden-10);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background: light-dark(@dark-blue-40, @golden-40);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.tag-team-controller {
|
.tag-team-controller {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
||||||
|
|
@ -43,3 +43,5 @@
|
||||||
@import './risk-it-all/sheet.less';
|
@import './risk-it-all/sheet.less';
|
||||||
|
|
||||||
@import './character-reset/sheet.less';
|
@import './character-reset/sheet.less';
|
||||||
|
|
||||||
|
@import './compendiumBrowserPackDialog/sheet.less';
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type='checkbox'] {
|
||||||
|
&:indeterminate {
|
||||||
|
&::before {
|
||||||
|
content: '\f0fe';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
input[type='checkbox'],
|
input[type='checkbox'],
|
||||||
input[type='radio'] {
|
input[type='radio'] {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
|
||||||
|
|
@ -38,124 +38,6 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
details[open] {
|
|
||||||
.fa-chevron-down {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-move {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.fa-chevron-down {
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
margin: 8px 8px 0;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
width: -webkit-fill-available;
|
|
||||||
gap: 5px;
|
|
||||||
border-bottom: 1px solid @golden;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: @golden-10;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-img {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 3px;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5px;
|
|
||||||
color: @beige;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: var(--font-size-20);
|
|
||||||
color: @golden;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: var(--font-size-12);
|
|
||||||
color: @beige;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
padding: 8px;
|
|
||||||
|
|
||||||
.summons-header {
|
|
||||||
font-size: var(--font-size-14);
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
span {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
content: ' ';
|
|
||||||
height: 1px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.summons-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
.summon-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
.summon-label-container {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ability-card-footer {
|
.ability-card-footer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
|
||||||
|
|
@ -228,6 +228,15 @@
|
||||||
font-size: var(--font-size-12);
|
font-size: var(--font-size-12);
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
|
|
||||||
|
.roll-part-title {
|
||||||
|
text-align: center;
|
||||||
|
font-family: @font-subtitle;
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
font-weight: bold;
|
||||||
|
color: light-dark(@dark-blue, var(--text-color));
|
||||||
|
margin-bottom: -2px;
|
||||||
|
}
|
||||||
|
|
||||||
> .roll-part-header {
|
> .roll-part-header {
|
||||||
font-size: var(--font-size-14);
|
font-size: var(--font-size-14);
|
||||||
}
|
}
|
||||||
|
|
@ -286,6 +295,7 @@
|
||||||
|
|
||||||
> :first-child:not(.target-selector) {
|
> :first-child:not(.target-selector) {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
> :last-child {
|
> :last-child {
|
||||||
|
|
@ -573,6 +583,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-roll .description-section {
|
||||||
|
.roll-part-content {
|
||||||
|
.dice-tooltip {
|
||||||
|
.wrapper {
|
||||||
|
i {
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> :first-child:not(.target-selector) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.roll-buttons {
|
.roll-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|
@ -590,5 +624,124 @@
|
||||||
.dice-roll .dice-tooltip fieldset {
|
.dice-roll .dice-tooltip fieldset {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
details[open] {
|
||||||
|
.fa-chevron-down {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-move {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.fa-chevron-down {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
margin: 8px 8px 0;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
gap: 5px;
|
||||||
|
border-bottom: 1px solid @golden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: @golden-10;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-img {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 3px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
color: @beige;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
color: @golden;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
color: @beige;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.summons-header {
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
content: ' ';
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, light-dark(@dark-blue, @golden) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
background: linear-gradient(90deg, light-dark(@dark-blue, @golden) 0%, rgba(0, 0, 0, 0) 100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.summons-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.summon-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.summon-label-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@
|
||||||
li[role='option'] {
|
li[role='option'] {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
|
||||||
font-size: var(--font-size-14);
|
font-size: var(--font-size-14);
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "daggerheart",
|
"id": "daggerheart",
|
||||||
"title": "Daggerheart",
|
"title": "Daggerheart",
|
||||||
"description": "An unofficial implementation of the Daggerheart system",
|
"description": "An unofficial implementation of the Daggerheart system",
|
||||||
"version": "1.6.4",
|
"version": "1.7.0",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "13.346",
|
"minimum": "13.346",
|
||||||
"verified": "13.351",
|
"verified": "13.351",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<footer>
|
||||||
|
<button data-action="finish">{{localize "Save Settings"}}</button>
|
||||||
|
</footer>
|
||||||
36
templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs
Normal file
36
templates/dialogs/compendiumBrowserSettingsDialog/packs.hbs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<div>
|
||||||
|
<div class="types-container">
|
||||||
|
{{#each typePackCollections as |type|}}
|
||||||
|
<div class="type-container">
|
||||||
|
<label>{{type.label}}</label>
|
||||||
|
|
||||||
|
<div class="sources-container">
|
||||||
|
{{#each type.sources as |source|}}
|
||||||
|
<div class="source-container">
|
||||||
|
<div class="source-inner-container">
|
||||||
|
<div class="source-inner-label-container">
|
||||||
|
<a
|
||||||
|
data-action="toggleSource" data-source="{{@key}}" data-type="{{@../key}}"
|
||||||
|
data-tooltip="{{#if source.checked}}{{localize "DAGGERHEART.APPLICATIONS.CompendiumBrowserSettings.disableSource"}}{{else}}{{localize "DAGGERHEART.APPLICATIONS.CompendiumBrowserSettings.enableSource"}}{{/if}}"
|
||||||
|
>
|
||||||
|
<i class="fa-solid {{#if source.checked}}fa-toggle-on{{else}}fa-toggle-off{{/if}}"></i>
|
||||||
|
</a>
|
||||||
|
<label>{{source.label}}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="checks-container {{#unless source.checked}}collapsed{{/unless}}">
|
||||||
|
{{#each source.packs as |pack|}}
|
||||||
|
<div class="check-container">
|
||||||
|
<input type="checkbox" class="pack-checkbox" data-type="{{pack.type}}" data-pack="{{pack.pack}}" {{checked pack.checked}} />
|
||||||
|
<label>{{pack.label}}</label>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
<header class="dialog-header">
|
<header class="dialog-header">
|
||||||
<div class="dialog-header-inner">
|
<div class="dialog-header-inner">
|
||||||
<h1>
|
<h1>{{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}}</h1>
|
||||||
{{#if reactionOverride}}
|
|
||||||
{{localize "DAGGERHEART.CONFIG.FeatureForm.reaction"}}
|
|
||||||
{{else}}
|
|
||||||
{{ifThen rollConfig.headerTitle rollConfig.headerTitle rollConfig.title}}
|
|
||||||
{{/if}}
|
|
||||||
{{#if showReaction}}
|
{{#if showReaction}}
|
||||||
<button class="reaction-roll-controller {{#if reactionOverride}}active{{/if}}" data-action="toggleReaction" data-tooltip-text="{{localize "DAGGERHEART.GENERAL.reactionRoll"}}">
|
<div class="reaction-chip {{#if reactionOverride}}selected{{/if}}" data-action="toggleReaction">
|
||||||
<i class="fa-solid fa-reply"></i>
|
<span><i class="{{ifThen reactionOverride "fa-solid" "fa-regular"}} fa-circle"></i></span>
|
||||||
</button>
|
<span class="label">{{localize "DAGGERHEART.GENERAL.reactionRoll"}}</span>
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
{{#if (and @root.hasRoll @root.activeTagTeamRoll)}}
|
{{#if (and @root.hasRoll @root.activeTagTeamRoll)}}
|
||||||
<div class="tag-team-controller {{#if @root.tagTeamSelected}}selected{{/if}}" data-action="toggleTagTeamRoll">
|
<div class="tag-team-controller {{#if @root.tagTeamSelected}}selected{{/if}}" data-action="toggleTagTeamRoll">
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@
|
||||||
{{#if name}}
|
{{#if name}}
|
||||||
<div class="experience-chip {{#if (includes ../selectedExperiences id)}}selected{{/if}}" data-action="selectExperience" data-key="{{id}}" data-tooltip="{{this.description}}">
|
<div class="experience-chip {{#if (includes ../selectedExperiences id)}}selected{{/if}}" data-action="selectExperience" data-key="{{id}}" data-tooltip="{{this.description}}">
|
||||||
<span><i class="{{ifThen (includes ../selectedExperiences id) "fa-solid" "fa-regular"}} fa-circle"></i></span>
|
<span><i class="{{ifThen (includes ../selectedExperiences id) "fa-solid" "fa-regular"}} fa-circle"></i></span>
|
||||||
<span class="label">{{name}} +{{value}}</span>
|
<span class="label">{{name}} {{numberFormat value sign=true}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@
|
||||||
{{#each document.system.experiences as |experience id|}}
|
{{#each document.system.experiences as |experience id|}}
|
||||||
<div class="experience-row" data-tooltip-text="{{experience.description}}">
|
<div class="experience-row" data-tooltip-text="{{experience.description}}">
|
||||||
<span class="experience-value">
|
<span class="experience-value">
|
||||||
+{{experience.value}}
|
{{numberFormat experience.value sign=true}}
|
||||||
</span>
|
</span>
|
||||||
<span class="experience-name">{{experience.name}}</span>
|
<span class="experience-name">{{experience.name}}</span>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ Parameters:
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.system.inVault 'sendToLoadout' 'sendToVault' }}">
|
||||||
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
<i class="fa-solid {{ifThen item.system.inVault 'fa-arrow-up' 'fa-arrow-down'}}"></i>
|
||||||
</a>
|
</a>
|
||||||
{{else if (eq type 'effect')}}
|
{{else if (and (eq type 'effect') (not (eq item.type 'beastform')))}}
|
||||||
<a data-action="toggleEffect"
|
<a data-action="toggleEffect"
|
||||||
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.disabled 'enableEffect' 'disableEffect' }}">
|
data-tooltip="DAGGERHEART.UI.Tooltip.{{ifThen item.disabled 'enableEffect' 'disableEffect' }}">
|
||||||
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}"></i>
|
<i class="{{ifThen item.disabled 'fa-solid fa-toggle-off' 'fa-solid fa-toggle-on'}}"></i>
|
||||||
|
|
|
||||||
11
templates/ui/chat/parts/description-part.hbs
Normal file
11
templates/ui/chat/parts/description-part.hbs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="roll-part dice-roll description-section" data-action="expandRoll">
|
||||||
|
<div class="roll-part-header"><div><span>{{localize "DAGGERHEART.GENERAL.description"}}</span></div></div>
|
||||||
|
|
||||||
|
<div class="roll-part-content description-content">
|
||||||
|
<div class="dice-tooltip">
|
||||||
|
<div class="wrapper">
|
||||||
|
<i>{{{actionDescription}}}</i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
<div class="chat-roll">
|
<div class="chat-roll">
|
||||||
<div class="roll-part-header"><span>{{title}}</span></div>
|
<div class="roll-part-title"><span>{{title}}</span></div>
|
||||||
{{#if hasRoll}}{{> 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs'}}{{/if}}
|
{{#if actionDescription}}{{> 'systems/daggerheart/templates/ui/chat/parts/description-part.hbs'}}{{/if}}
|
||||||
|
{{#if hasRoll}}
|
||||||
|
<div class="roll-part-header"><span>{{localize "Result"}}</span></div>
|
||||||
|
{{> 'systems/daggerheart/templates/ui/chat/parts/roll-part.hbs'}}
|
||||||
|
{{/if}}
|
||||||
{{#if (or hasDamage hasHealing)}}{{> 'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs'}}{{/if}}
|
{{#if (or hasDamage hasHealing)}}{{> 'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs'}}{{/if}}
|
||||||
{{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
|
{{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
|
||||||
<div class="roll-part-header"><div></div></div>
|
<div class="roll-part-header"><div></div></div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<div class="compendium-sidebar">
|
<div class="compendium-sidebar">
|
||||||
|
{{#if isGM}}<button data-action="openSettings"><i class="fa-solid fa-gear"></i> {{localize "DAGGERHEART.UI.ItemBrowser.browserSettings"}}</button>{{/if}}
|
||||||
<div class="folder-list">
|
<div class="folder-list">
|
||||||
{{#each compendiums}}
|
{{#each compendiums}}
|
||||||
<div class="{{#if selected}} is-selected{{/if}}" data-action="selectFolder" data-folder-id="{{id}}" {{#if folders.length}}data-tooltip="DAGGERHEART.UI.Tooltip.rightClickExtand" data-tooltip-direction="RIGHT"{{/if}}>{{label}}</div>
|
<div class="{{#if selected}} is-selected{{/if}}" data-action="selectFolder" data-folder-id="{{id}}" {{#if folders.length}}data-tooltip="DAGGERHEART.UI.Tooltip.rightClickExtend" data-tooltip-direction="RIGHT"{{/if}}>{{label}}</div>
|
||||||
{{#if folders.length}}
|
{{#if folders.length}}
|
||||||
<div class="subfolder-list">
|
<div class="subfolder-list">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const foundryPath = process.env.FOUNDRY_MAIN_PATH || '../../../../FoundryDev/mai
|
||||||
const dataPath = process.env.FOUNDRY_DATA_PATH || '../../../';
|
const dataPath = process.env.FOUNDRY_DATA_PATH || '../../../';
|
||||||
|
|
||||||
// Run the original command with proper environment
|
// Run the original command with proper environment
|
||||||
const args = ['rollup -c --watch', `node "${foundryPath}" --dataPath="${dataPath}" --noupnp`, 'gulp'];
|
const args = ['rollup -c --watch', `node "\"${foundryPath}\"" --dataPath="${dataPath}" --noupnp`, 'gulp'];
|
||||||
|
|
||||||
spawn('npx', ['concurrently', ...args.map(arg => `"${arg}"`)], {
|
spawn('npx', ['concurrently', ...args.map(arg => `"${arg}"`)], {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue