mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-21 23:13:39 +02:00
Merged main
This commit is contained in:
commit
b87e630a0a
84 changed files with 2046 additions and 452 deletions
|
|
@ -233,6 +233,11 @@ Hooks.once('init', () => {
|
||||||
return handlebarsRegistration();
|
return handlebarsRegistration();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('i18nInit', () => {
|
||||||
|
// Setup homebrew resources
|
||||||
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).refreshConfig();
|
||||||
|
});
|
||||||
|
|
||||||
Hooks.on('setup', () => {
|
Hooks.on('setup', () => {
|
||||||
CONFIG.statusEffects = [
|
CONFIG.statusEffects = [
|
||||||
...CONFIG.statusEffects.filter(x => !['dead', 'unconscious'].includes(x.id)),
|
...CONFIG.statusEffects.filter(x => !['dead', 'unconscious'].includes(x.id)),
|
||||||
|
|
|
||||||
57
lang/en.json
57
lang/en.json
|
|
@ -76,6 +76,15 @@
|
||||||
"invalidDrop": "You can only drop Actor entities to summon.",
|
"invalidDrop": "You can only drop Actor entities to summon.",
|
||||||
"chatMessageTitle": "Test2",
|
"chatMessageTitle": "Test2",
|
||||||
"chatMessageHeaderTitle": "Summoning"
|
"chatMessageHeaderTitle": "Summoning"
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"name": "Transform",
|
||||||
|
"tooltip": "Transform one actor into another",
|
||||||
|
"noTransformActor": "There is no assigned actor to transform into",
|
||||||
|
"transformActorMissing": "The assigned actor to transform into does not exist. It was probably deleted or moved in/out of a compendium",
|
||||||
|
"canvasError": "There is no active scene.",
|
||||||
|
"prototypeError": "You can only use a transform action from a Token",
|
||||||
|
"actorLinkError": "You cannot transform a token with Actor Link set to true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Config": {
|
"Config": {
|
||||||
|
|
@ -131,6 +140,12 @@
|
||||||
},
|
},
|
||||||
"summon": {
|
"summon": {
|
||||||
"dropSummonsHere": "Drop Summons Here"
|
"dropSummonsHere": "Drop Summons Here"
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"dropTransformHere": "Drop Transform Here",
|
||||||
|
"actorIsMissing": "The linked actor is missing. You should delete this link.",
|
||||||
|
"clearHitPoints": "Clear Hitpoints",
|
||||||
|
"clearStress": "Clear Stress"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -1054,6 +1069,10 @@
|
||||||
"fear": "Fear",
|
"fear": "Fear",
|
||||||
"spotlight": "Spotlight"
|
"spotlight": "Spotlight"
|
||||||
},
|
},
|
||||||
|
"DaggerheartDiceAnimationEvents": {
|
||||||
|
"critical": { "name": "Critical" },
|
||||||
|
"higher": { "name": "Highest Roll" }
|
||||||
|
},
|
||||||
"DamageType": {
|
"DamageType": {
|
||||||
"physical": {
|
"physical": {
|
||||||
"name": "Physical",
|
"name": "Physical",
|
||||||
|
|
@ -2277,6 +2296,7 @@
|
||||||
"identify": "Identity",
|
"identify": "Identity",
|
||||||
"imagePath": "Image Path",
|
"imagePath": "Image Path",
|
||||||
"inactiveEffects": "Inactive Effects",
|
"inactiveEffects": "Inactive Effects",
|
||||||
|
"initial": "Initial",
|
||||||
"inventory": "Inventory",
|
"inventory": "Inventory",
|
||||||
"itemResource": "Item Resource",
|
"itemResource": "Item Resource",
|
||||||
"itemQuantity": "Item Quantity",
|
"itemQuantity": "Item Quantity",
|
||||||
|
|
@ -2304,6 +2324,7 @@
|
||||||
"plurial": "Players"
|
"plurial": "Players"
|
||||||
},
|
},
|
||||||
"portrait": "Portrait",
|
"portrait": "Portrait",
|
||||||
|
"preview": "Preview",
|
||||||
"proficiency": "Proficiency",
|
"proficiency": "Proficiency",
|
||||||
"quantity": "Quantity",
|
"quantity": "Quantity",
|
||||||
"range": "Range",
|
"range": "Range",
|
||||||
|
|
@ -2644,6 +2665,14 @@
|
||||||
"title": "Triggers"
|
"title": "Triggers"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Metagaming": {
|
||||||
|
"FIELDS": {
|
||||||
|
"hideObserverPermissionInChat": {
|
||||||
|
"label": "Hide Chat Info From Players",
|
||||||
|
"hint": "Information such as hit/miss on attack rolls against adversaries will be hidden"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Homebrew": {
|
"Homebrew": {
|
||||||
"newDowntimeMove": "Downtime Move",
|
"newDowntimeMove": "Downtime Move",
|
||||||
"downtimeMove": "Downtime Move",
|
"downtimeMove": "Downtime Move",
|
||||||
|
|
@ -2658,6 +2687,8 @@
|
||||||
"resetMovesText": "Are you sure you want to reset?",
|
"resetMovesText": "Are you sure you want to reset?",
|
||||||
"deleteItemTitle": "Delete Homebrew Item",
|
"deleteItemTitle": "Delete Homebrew Item",
|
||||||
"deleteItemText": "Are you sure you want to delete the item?",
|
"deleteItemText": "Are you sure you want to delete the item?",
|
||||||
|
"deleteResourceTitle": "Delete Homebrew Resource",
|
||||||
|
"deleteResourceText": "Are you sure you want to delete the resource?",
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
"maxFear": { "label": "Max Fear" },
|
"maxFear": { "label": "Max Fear" },
|
||||||
"maxHope": { "label": "Max Hope" },
|
"maxHope": { "label": "Max Hope" },
|
||||||
|
|
@ -2666,6 +2697,13 @@
|
||||||
"label": "Max Cards in Loadout",
|
"label": "Max Cards in Loadout",
|
||||||
"hint": "Set to blank or 0 for unlimited maximum"
|
"hint": "Set to blank or 0 for unlimited maximum"
|
||||||
},
|
},
|
||||||
|
"resources": {
|
||||||
|
"resources": {
|
||||||
|
"value": { "label": "Icon" },
|
||||||
|
"isIcon": { "label": "Font Awesome Icon" },
|
||||||
|
"noColorFilter": { "label": "Disable Color Filter" }
|
||||||
|
}
|
||||||
|
},
|
||||||
"maxDomains": { "label": "Max Class Domains", "hint": "Max domains you can set on a class" }
|
"maxDomains": { "label": "Max Class Domains", "hint": "Max domains you can set on a class" }
|
||||||
},
|
},
|
||||||
"currency": {
|
"currency": {
|
||||||
|
|
@ -2694,6 +2732,13 @@
|
||||||
"adversaryType": {
|
"adversaryType": {
|
||||||
"title": "Custom Adversary Types",
|
"title": "Custom Adversary Types",
|
||||||
"newType": "Adversary Type"
|
"newType": "Adversary Type"
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"typeTitle": "{type} Resources",
|
||||||
|
"filledIcon": "Filled Icon",
|
||||||
|
"emptyIcon": "Empty Icon",
|
||||||
|
"resourceIdentifier": "Resource Identifier",
|
||||||
|
"setResourceIdentifier": "Set Resource Identifier"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
|
|
@ -2703,6 +2748,11 @@
|
||||||
"label": "Configure Automation",
|
"label": "Configure Automation",
|
||||||
"hint": "Various settings automating resource management and more"
|
"hint": "Various settings automating resource management and more"
|
||||||
},
|
},
|
||||||
|
"metagaming": {
|
||||||
|
"name": "Metagaming Settings",
|
||||||
|
"label": "Configure Metagaming",
|
||||||
|
"hint": "Various settings controlling the flow of information to players"
|
||||||
|
},
|
||||||
"homebrew": {
|
"homebrew": {
|
||||||
"name": "Homebrew Settings",
|
"name": "Homebrew Settings",
|
||||||
"label": "Configure Homebrew",
|
"label": "Configure Homebrew",
|
||||||
|
|
@ -2728,7 +2778,12 @@
|
||||||
"colorset": "Theme",
|
"colorset": "Theme",
|
||||||
"material": "Material",
|
"material": "Material",
|
||||||
"system": "Dice Preset",
|
"system": "Dice Preset",
|
||||||
"font": "Font"
|
"font": "Font",
|
||||||
|
"critical": "Duality Critical Animation",
|
||||||
|
"diceAppearance": "Dice Appearance",
|
||||||
|
"animations": "Animations",
|
||||||
|
"defaultAnimations": "Set Animations As Player Defaults",
|
||||||
|
"previewAnimation": "Preview Animation"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"variantRules": {
|
"variantRules": {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export { default as DhAppearanceSettings } from './appearanceSettings.mjs';
|
export { default as DhAppearanceSettings } from './appearanceSettings.mjs';
|
||||||
export { default as DhAutomationSettings } from './automationSettings.mjs';
|
export { default as DhAutomationSettings } from './automationSettings.mjs';
|
||||||
export { default as DhHomebrewSettings } from './homebrewSettings.mjs';
|
export { default as DhHomebrewSettings } from './homebrewSettings.mjs';
|
||||||
|
export { default as DhMetagamingSettings } from './metagamingSettings.mjs';
|
||||||
export { default as DhVariantRuleSettings } from './variantRuleSettings.mjs';
|
export { default as DhVariantRuleSettings } from './variantRuleSettings.mjs';
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
tag: 'form',
|
tag: 'form',
|
||||||
id: 'daggerheart-appearance-settings',
|
id: 'daggerheart-appearance-settings',
|
||||||
classes: ['daggerheart', 'dialog', 'dh-style', 'setting'],
|
classes: ['daggerheart', 'dialog', 'dh-style', 'setting', 'appearance-settings'],
|
||||||
position: { width: '600', height: 'auto' },
|
position: { width: '600', height: 'auto' },
|
||||||
window: {
|
window: {
|
||||||
title: 'DAGGERHEART.SETTINGS.Menu.title',
|
title: 'DAGGERHEART.SETTINGS.Menu.title',
|
||||||
|
|
@ -70,6 +70,14 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
htmlElement
|
||||||
|
.querySelector('.default-animations-input')
|
||||||
|
?.addEventListener('change', this.toggleSFXOverride.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
_configureRenderParts(options) {
|
_configureRenderParts(options) {
|
||||||
const parts = super._configureRenderParts(options);
|
const parts = super._configureRenderParts(options);
|
||||||
|
|
@ -83,15 +91,20 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _prepareContext(options) {
|
async _prepareContext(options) {
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
if (options.isFirstRender)
|
if (options.isFirstRender) {
|
||||||
this.setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
this.setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
||||||
|
this.globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
context.setting = this.setting;
|
context.setting = this.setting;
|
||||||
|
context.globalOverrides = this.globalOverrides;
|
||||||
context.fields = this.setting.schema.fields;
|
context.fields = this.setting.schema.fields;
|
||||||
|
|
||||||
context.tabs = this._prepareTabs('general');
|
context.tabs = this._prepareTabs('general');
|
||||||
context.dsnTabs = this._prepareTabs('diceSoNice');
|
context.dsnTabs = this._prepareTabs('diceSoNice');
|
||||||
|
|
||||||
|
context.isGM = game.user.isGM;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,6 +133,9 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
async prepareDiceSoNiceContext(context) {
|
async prepareDiceSoNiceContext(context) {
|
||||||
|
context.animationEvents = CONFIG.DH.GENERAL.daggerheartDiceAnimationEvents;
|
||||||
|
context.previewAnimation = this.previewAnimation;
|
||||||
|
|
||||||
context.diceSoNiceTextures = Object.entries(game.dice3d.exports.TEXTURELIST).reduce(
|
context.diceSoNiceTextures = Object.entries(game.dice3d.exports.TEXTURELIST).reduce(
|
||||||
(acc, [k, v]) => ({
|
(acc, [k, v]) => ({
|
||||||
...acc,
|
...acc,
|
||||||
|
|
@ -146,6 +162,13 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
);
|
);
|
||||||
context.diceSoNiceFonts = game.dice3d.exports.Utils.prepareFontList();
|
context.diceSoNiceFonts = game.dice3d.exports.Utils.prepareFontList();
|
||||||
|
|
||||||
|
const getAnimationsOptions = key => {
|
||||||
|
const fields = context.fields.diceSoNice.fields[key].fields.sfx.fields;
|
||||||
|
return {
|
||||||
|
higher: fields.higher.fields.class.choices
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
foundry.utils.mergeObject(
|
foundry.utils.mergeObject(
|
||||||
context.dsnTabs,
|
context.dsnTabs,
|
||||||
['hope', 'fear', 'advantage', 'disadvantage'].reduce(
|
['hope', 'fear', 'advantage', 'disadvantage'].reduce(
|
||||||
|
|
@ -153,7 +176,8 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
...acc,
|
...acc,
|
||||||
[key]: {
|
[key]: {
|
||||||
values: this.setting.diceSoNice[key],
|
values: this.setting.diceSoNice[key],
|
||||||
fields: this.setting.schema.getField(`diceSoNice.${key}`).fields
|
fields: this.setting.schema.getField(`diceSoNice.${key}`).fields,
|
||||||
|
animations: ['hope', 'fear'].includes(key) ? getAnimationsOptions(key) : {}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{}
|
{}
|
||||||
|
|
@ -169,13 +193,20 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
* @param {foundry.applications.ux.FormDataExtended} formData
|
* @param {foundry.applications.ux.FormDataExtended} formData
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async #onSubmit(event, form, formData) {
|
static async #onSubmit(_event, _form, formData) {
|
||||||
const data = this.setting.schema.clean(foundry.utils.expandObject(formData.object));
|
const data = this.setting.schema.clean(foundry.utils.expandObject(formData.object));
|
||||||
|
|
||||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, data);
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
async toggleSFXOverride(event) {
|
||||||
|
await this.globalOverrides.diceSoNiceSFXUpdate(this.setting, event.target.checked);
|
||||||
|
this.globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit the configuration form.
|
* Submit the configuration form.
|
||||||
* @this {DHAppearanceSettings}
|
* @this {DHAppearanceSettings}
|
||||||
|
|
@ -183,13 +214,25 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
||||||
*/
|
*/
|
||||||
static async #onPreview(_, target) {
|
static async #onPreview(_, target) {
|
||||||
const formData = new foundry.applications.ux.FormDataExtended(target.closest('form'));
|
const formData = new foundry.applications.ux.FormDataExtended(target.closest('form'));
|
||||||
const { diceSoNice } = foundry.utils.expandObject(formData.object);
|
const { diceSoNice, ...rest } = foundry.utils.expandObject(formData.object);
|
||||||
const { key } = target.dataset;
|
const { key } = target.dataset;
|
||||||
const faces = ['advantage', 'disadvantage'].includes(key) ? 'd6' : 'd12';
|
const faces = ['advantage', 'disadvantage'].includes(key) ? 'd6' : 'd12';
|
||||||
const preset = await getDiceSoNicePreset(diceSoNice[key], faces);
|
const preset = await getDiceSoNicePreset(diceSoNice[key], faces);
|
||||||
const diceSoNiceRoll = await new foundry.dice.Roll(`1${faces}`).evaluate();
|
const diceSoNiceRoll = await new foundry.dice.Roll(`1${faces}`).evaluate();
|
||||||
diceSoNiceRoll.dice[0].options.appearance = preset.appearance;
|
diceSoNiceRoll.dice[0].options.appearance = preset.appearance;
|
||||||
diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile;
|
diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile;
|
||||||
|
|
||||||
|
const previewAnimation = rest[`${key}PreviewAnimation`];
|
||||||
|
const events = CONFIG.DH.GENERAL.daggerheartDiceAnimationEvents;
|
||||||
|
if (previewAnimation) {
|
||||||
|
if (previewAnimation === events.critical.id && diceSoNice.sfx.critical.class) {
|
||||||
|
diceSoNiceRoll.dice[0].options.sfx = { specialEffect: diceSoNice.sfx.critical.class };
|
||||||
|
}
|
||||||
|
if (previewAnimation === events.higher.id && diceSoNice[key].sfx.higher) {
|
||||||
|
diceSoNiceRoll.dice[0].options.sfx = { specialEffect: diceSoNice[key].sfx.higher.class };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, false);
|
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
|
||||||
};
|
};
|
||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
|
||||||
header: { template: 'systems/daggerheart/templates/settings/automation-settings/header.hbs' },
|
header: { template: 'systems/daggerheart/templates/settings/automation-settings/header.hbs' },
|
||||||
|
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||||
general: { template: 'systems/daggerheart/templates/settings/automation-settings/general.hbs' },
|
general: { template: 'systems/daggerheart/templates/settings/automation-settings/general.hbs' },
|
||||||
rules: { template: 'systems/daggerheart/templates/settings/automation-settings/deathMoves.hbs' },
|
rules: { template: 'systems/daggerheart/templates/settings/automation-settings/deathMoves.hbs' },
|
||||||
roll: { template: 'systems/daggerheart/templates/settings/automation-settings/roll.hbs' },
|
roll: { template: 'systems/daggerheart/templates/settings/automation-settings/roll.hbs' },
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { DhHomebrew } from '../../data/settings/_module.mjs';
|
import { DhHomebrew } from '../../data/settings/_module.mjs';
|
||||||
|
import { Resource } from '../../data/settings/Homebrew.mjs';
|
||||||
import { slugify } from '../../helpers/utils.mjs';
|
import { slugify } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
@ -44,6 +45,9 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
addAdversaryType: this.addAdversaryType,
|
addAdversaryType: this.addAdversaryType,
|
||||||
deleteAdversaryType: this.deleteAdversaryType,
|
deleteAdversaryType: this.deleteAdversaryType,
|
||||||
selectAdversaryType: this.selectAdversaryType,
|
selectAdversaryType: this.selectAdversaryType,
|
||||||
|
addResource: this.addResource,
|
||||||
|
removeResource: this.removeResource,
|
||||||
|
resetResourceImage: this.resetResourceImage,
|
||||||
save: this.save,
|
save: this.save,
|
||||||
resetTokenSizes: this.resetTokenSizes,
|
resetTokenSizes: this.resetTokenSizes,
|
||||||
reset: this.reset
|
reset: this.reset
|
||||||
|
|
@ -56,6 +60,10 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' },
|
settings: { template: 'systems/daggerheart/templates/settings/homebrew-settings/settings.hbs' },
|
||||||
domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' },
|
domains: { template: 'systems/daggerheart/templates/settings/homebrew-settings/domains.hbs' },
|
||||||
types: { template: 'systems/daggerheart/templates/settings/homebrew-settings/types.hbs' },
|
types: { template: 'systems/daggerheart/templates/settings/homebrew-settings/types.hbs' },
|
||||||
|
resources: {
|
||||||
|
template: 'systems/daggerheart/templates/settings/homebrew-settings/resources.hbs',
|
||||||
|
scrollable: ['.resource-types-container']
|
||||||
|
},
|
||||||
itemTypes: { template: 'systems/daggerheart/templates/settings/homebrew-settings/itemFeatures.hbs' },
|
itemTypes: { template: 'systems/daggerheart/templates/settings/homebrew-settings/itemFeatures.hbs' },
|
||||||
downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' },
|
downtime: { template: 'systems/daggerheart/templates/settings/homebrew-settings/downtime.hbs' },
|
||||||
footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' }
|
footer: { template: 'systems/daggerheart/templates/settings/homebrew-settings/footer.hbs' }
|
||||||
|
|
@ -64,7 +72,14 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
static TABS = {
|
static TABS = {
|
||||||
main: {
|
main: {
|
||||||
tabs: [{ id: 'settings' }, { id: 'domains' }, { id: 'types' }, { id: 'itemFeatures' }, { id: 'downtime' }],
|
tabs: [
|
||||||
|
{ id: 'settings' },
|
||||||
|
{ id: 'domains' },
|
||||||
|
{ id: 'types' },
|
||||||
|
{ id: 'resources' },
|
||||||
|
{ id: 'itemFeatures' },
|
||||||
|
{ id: 'downtime' }
|
||||||
|
],
|
||||||
initial: 'settings',
|
initial: 'settings',
|
||||||
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||||
}
|
}
|
||||||
|
|
@ -77,9 +92,17 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
for (const element of htmlElement.querySelectorAll('.path-field input'))
|
||||||
|
element.addEventListener('change', this.toggleResourceIsIcon.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.settingFields = this.settings;
|
context.settingFields = this.settings;
|
||||||
|
context.schemaFields = context.settingFields.schema.fields;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +126,8 @@ 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 'resources':
|
||||||
|
break;
|
||||||
case 'downtime':
|
case 'downtime':
|
||||||
context.restOptions = {
|
context.restOptions = {
|
||||||
shortRest: CONFIG.DH.GENERAL.defaultRestOptions.shortRest(),
|
shortRest: CONFIG.DH.GENERAL.defaultRestOptions.shortRest(),
|
||||||
|
|
@ -124,6 +149,33 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async toggleResourceIsIcon(event) {
|
||||||
|
const element = event.target.closest('.resource-icon-container');
|
||||||
|
const { actorType, resourceKey, imageKey } = element.dataset;
|
||||||
|
|
||||||
|
const current = this.settings.resources[actorType].resources[resourceKey].images[imageKey];
|
||||||
|
await this.settings.updateSource({
|
||||||
|
[`resources.${actorType}.resources.${resourceKey}.images.${imageKey}`]: {
|
||||||
|
isIcon: !current.isIcon,
|
||||||
|
value: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async resetResourceImage(_event, button) {
|
||||||
|
const element = button.closest('.resource-icon-container');
|
||||||
|
const { actorType, resourceKey, imageKey } = element.dataset;
|
||||||
|
|
||||||
|
await this.settings.updateSource({
|
||||||
|
[`resources.${actorType}.resources.${resourceKey}.images.${imageKey}`]:
|
||||||
|
Resource.getDefaultImageData(imageKey)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
static async changeCurrencyIcon(_, target) {
|
static async changeCurrencyIcon(_, target) {
|
||||||
const type = target.dataset.currency;
|
const type = target.dataset.currency;
|
||||||
const currentIcon = this.settings.currency[type].icon;
|
const currentIcon = this.settings.currency[type].icon;
|
||||||
|
|
@ -466,6 +518,58 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async addResource(_, target) {
|
||||||
|
const { actorType } = target.dataset;
|
||||||
|
const content = new foundry.data.fields.StringField({
|
||||||
|
label: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.resources.resourceIdentifier'),
|
||||||
|
required: true
|
||||||
|
}).toFormGroup({}, { name: 'identifier', localize: true }).outerHTML;
|
||||||
|
|
||||||
|
async function callback(_, button) {
|
||||||
|
const identifier = button.form.elements.identifier.value;
|
||||||
|
if (!identifier) return;
|
||||||
|
|
||||||
|
const sluggedIdentifier = slugify(identifier);
|
||||||
|
|
||||||
|
await this.settings.updateSource({
|
||||||
|
[`resources.${actorType}.resources.${sluggedIdentifier}`]: Resource.getDefaultResourceData(identifier)
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
await foundry.applications.api.DialogV2.prompt({
|
||||||
|
content: content,
|
||||||
|
rejectClose: false,
|
||||||
|
modal: true,
|
||||||
|
ok: { callback: callback.bind(this) },
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.resources.setResourceIdentifier')
|
||||||
|
},
|
||||||
|
position: { width: 400 }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static async removeResource(_, target) {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.localize(`DAGGERHEART.SETTINGS.Homebrew.deleteResourceTitle`)
|
||||||
|
},
|
||||||
|
content: game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.deleteResourceText')
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
const { actorType, resourceKey } = target.dataset;
|
||||||
|
await this.settings.updateSource({
|
||||||
|
[`resources.${actorType}.resources.${resourceKey}`]: _del
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
static async save() {
|
static async save() {
|
||||||
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
|
||||||
this.close();
|
this.close();
|
||||||
|
|
|
||||||
62
module/applications/settings/metagamingSettings.mjs
Normal file
62
module/applications/settings/metagamingSettings.mjs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { DhMetagaming } from '../../data/settings/_module.mjs';
|
||||||
|
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
export default class DhMetagamingSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor() {
|
||||||
|
super({});
|
||||||
|
|
||||||
|
this.settings = new DhMetagaming(
|
||||||
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming).toObject()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.localize('DAGGERHEART.SETTINGS.Menu.title');
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
tag: 'form',
|
||||||
|
id: 'daggerheart-metagaming-settings',
|
||||||
|
classes: ['daggerheart', 'dh-style', 'dialog', 'setting'],
|
||||||
|
position: { width: '600', height: 'auto' },
|
||||||
|
window: {
|
||||||
|
icon: 'fa-solid fa-eye-low-vision'
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
reset: this.reset,
|
||||||
|
save: this.save
|
||||||
|
},
|
||||||
|
form: { handler: this.updateData, submitOnChange: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
static PARTS = {
|
||||||
|
header: { template: 'systems/daggerheart/templates/settings/metagaming-settings/header.hbs' },
|
||||||
|
general: { template: 'systems/daggerheart/templates/settings/metagaming-settings/general.hbs' },
|
||||||
|
footer: { template: 'systems/daggerheart/templates/settings/metagaming-settings/footer.hbs' }
|
||||||
|
};
|
||||||
|
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const context = await super._prepareContext(_options);
|
||||||
|
context.settingFields = this.settings;
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async updateData(_event, _element, formData) {
|
||||||
|
const updatedSettings = foundry.utils.expandObject(formData.object);
|
||||||
|
|
||||||
|
await this.settings.updateSource(updatedSettings);
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async reset() {
|
||||||
|
this.settings = new DhMetagaming();
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async save() {
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming, this.settings.toObject());
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
removeEffect: this.removeEffect,
|
removeEffect: this.removeEffect,
|
||||||
addElement: this.addElement,
|
addElement: this.addElement,
|
||||||
removeElement: this.removeElement,
|
removeElement: this.removeElement,
|
||||||
|
removeTransformActor: this.removeTransformActor,
|
||||||
editEffect: this.editEffect,
|
editEffect: this.editEffect,
|
||||||
addDamage: this.addDamage,
|
addDamage: this.addDamage,
|
||||||
removeDamage: this.removeDamage,
|
removeDamage: this.removeDamage,
|
||||||
|
|
@ -42,7 +43,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
submitOnChange: true,
|
submitOnChange: true,
|
||||||
closeOnSubmit: false
|
closeOnSubmit: false
|
||||||
},
|
},
|
||||||
dragDrop: [{ dragSelector: null, dropSelector: '#summon-drop-zone', handlers: ['_onDrop'] }]
|
dragDrop: [{ dragSelector: null, dropSelector: '[data-is-drop-zone]', handlers: ['_onDrop'] }]
|
||||||
};
|
};
|
||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
|
|
@ -121,6 +122,10 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
htmlElement.querySelectorAll('.summon-count-wrapper input').forEach(element => {
|
htmlElement.querySelectorAll('.summon-count-wrapper input').forEach(element => {
|
||||||
element.addEventListener('change', this.updateSummonCount.bind(this));
|
element.addEventListener('change', this.updateSummonCount.bind(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
htmlElement.querySelectorAll('.transform-resource input').forEach(element => {
|
||||||
|
element.addEventListener('change', this.updateTransformResource.bind(this));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
|
|
@ -134,6 +139,18 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
context.summons.push({ actor, count: summon.count });
|
context.summons.push({ actor, count: summon.count });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.source.transform) {
|
||||||
|
const actor = await foundry.utils.fromUuid(context.source.transform.actorUUID);
|
||||||
|
context.transform = {
|
||||||
|
...context.source.transform,
|
||||||
|
actor:
|
||||||
|
actor ??
|
||||||
|
(context.source.transform.actorUUID && !actor
|
||||||
|
? { error: game.i18n.localize('DAGGERHEART.ACTIONS.Settings.transform.actorIsMissing') }
|
||||||
|
: null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
context.openSection = this.openSection;
|
context.openSection = this.openSection;
|
||||||
context.tabs = this._getTabs(this.constructor.TABS);
|
context.tabs = this._getTabs(this.constructor.TABS);
|
||||||
context.config = CONFIG.DH;
|
context.config = CONFIG.DH;
|
||||||
|
|
@ -268,6 +285,12 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
if (doc) return doc.sheet.render({ force: true });
|
if (doc) return doc.sheet.render({ force: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async removeTransformActor() {
|
||||||
|
const data = this.action.toObject();
|
||||||
|
data.transform.actorUUID = null;
|
||||||
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
|
}
|
||||||
|
|
||||||
static addDamage(_event) {
|
static addDamage(_event) {
|
||||||
if (!this.action.damage.parts) return;
|
if (!this.action.damage.parts) return;
|
||||||
|
|
||||||
|
|
@ -324,7 +347,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
const data = this.action.toObject();
|
const data = this.action.toObject();
|
||||||
const key = button.dataset.key;
|
const key = button.dataset.key;
|
||||||
delete data.damage.parts[key];
|
delete data.damage.parts[key];
|
||||||
data.damage.parts[`-=${key}`] = null;
|
data.damage.parts[`${key}`] = _del;
|
||||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,6 +414,14 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTransformResource(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const data = this.action.toObject();
|
||||||
|
data.transform.resourceRefresh[event.target.dataset.resource] = event.target.checked;
|
||||||
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
|
}
|
||||||
|
|
||||||
/** Specific implementation in extending classes **/
|
/** Specific implementation in extending classes **/
|
||||||
static async addEffect(_event) {}
|
static async addEffect(_event) {}
|
||||||
static removeEffect(_event, _button) {}
|
static removeEffect(_event, _button) {}
|
||||||
|
|
@ -409,6 +440,18 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dropZone = event.target.closest('[data-is-drop-zone]');
|
||||||
|
if (!dropZone) return;
|
||||||
|
|
||||||
|
switch (dropZone.id) {
|
||||||
|
case 'summon-drop-zone':
|
||||||
|
return this.onSummonDrop(data);
|
||||||
|
case 'transform-drop-zone':
|
||||||
|
return this.onTransformDrop(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async onSummonDrop(data) {
|
||||||
const actionData = this.action.toObject();
|
const actionData = this.action.toObject();
|
||||||
let countvalue = 1;
|
let countvalue = 1;
|
||||||
for (const entry of actionData.summon) {
|
for (const entry of actionData.summon) {
|
||||||
|
|
@ -425,4 +468,10 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
actionData.summon.push({ actorUUID: data.uuid, count: countvalue });
|
actionData.summon.push({ actorUUID: data.uuid, count: countvalue });
|
||||||
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) });
|
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onTransformDrop(data) {
|
||||||
|
const actionData = this.action.toObject();
|
||||||
|
actionData.transform.actorUUID = data.uuid;
|
||||||
|
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
handleResourceDice: CharacterSheet.#handleResourceDice,
|
handleResourceDice: CharacterSheet.#handleResourceDice,
|
||||||
advanceResourceDie: CharacterSheet.#advanceResourceDie,
|
advanceResourceDie: CharacterSheet.#advanceResourceDie,
|
||||||
cancelBeastform: CharacterSheet.#cancelBeastform,
|
cancelBeastform: CharacterSheet.#cancelBeastform,
|
||||||
|
toggleResourceManagement: CharacterSheet.#toggleResourceManagement,
|
||||||
useDowntime: this.useDowntime,
|
useDowntime: this.useDowntime,
|
||||||
viewParty: CharacterSheet.#viewParty
|
viewParty: CharacterSheet.#viewParty
|
||||||
},
|
},
|
||||||
|
|
@ -226,6 +227,9 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
async _preparePartContext(partId, context, options) {
|
async _preparePartContext(partId, context, options) {
|
||||||
context = await super._preparePartContext(partId, context, options);
|
context = await super._preparePartContext(partId, context, options);
|
||||||
switch (partId) {
|
switch (partId) {
|
||||||
|
case 'header':
|
||||||
|
await this._prepareHeaderContext(context, options);
|
||||||
|
break;
|
||||||
case 'loadout':
|
case 'loadout':
|
||||||
await this._prepareLoadoutContext(context, options);
|
await this._prepareLoadoutContext(context, options);
|
||||||
break;
|
break;
|
||||||
|
|
@ -240,6 +244,12 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _prepareHeaderContext(context, _options) {
|
||||||
|
context.hasExtraResources = Object.keys(CONFIG.DH.RESOURCE.character.all).some(
|
||||||
|
key => !CONFIG.DH.RESOURCE.character.base[key]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare render context for the Loadout part.
|
* Prepare render context for the Loadout part.
|
||||||
* @param {ApplicationRenderContext} context
|
* @param {ApplicationRenderContext} context
|
||||||
|
|
@ -942,6 +952,78 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #toggleResourceManagement(event, button) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const existingTooltip = document.body.querySelector('.locked-tooltip .resource-management-container');
|
||||||
|
if (existingTooltip) {
|
||||||
|
game.tooltip.dismissLockedTooltips();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extraResources = Object.values(CONFIG.DH.RESOURCE.character.all).reduce((acc, resource) => {
|
||||||
|
if (CONFIG.DH.RESOURCE.character.base[resource.id]) return acc;
|
||||||
|
|
||||||
|
const resourceData = this.document.system.resources[resource.id];
|
||||||
|
acc[resource.id] = {
|
||||||
|
id: resource.id,
|
||||||
|
label: game.i18n.localize(resource.label),
|
||||||
|
value: resourceData.value,
|
||||||
|
max: resourceData.max,
|
||||||
|
fullIcon: resource.images?.full ?? { value: 'fa-solid fa-circle', isIcon: true },
|
||||||
|
emptyIcon: resource.images?.empty ?? { value: 'fa-regular fa-circle', isIcon: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const html = document.createElement('div');
|
||||||
|
html.innerHTML = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
`systems/daggerheart/templates/ui/tooltip/resourceManagement.hbs`,
|
||||||
|
{
|
||||||
|
resources: extraResources
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const target = button.closest('.resource-section');
|
||||||
|
|
||||||
|
game.tooltip.dismissLockedTooltips();
|
||||||
|
game.tooltip.activate(target, {
|
||||||
|
html,
|
||||||
|
locked: true,
|
||||||
|
cssClass: 'bordered-tooltip',
|
||||||
|
direction: 'DOWN',
|
||||||
|
noOffset: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const resourceManager = target.querySelector('.resource-manager');
|
||||||
|
resourceManager.classList.toggle('inverted');
|
||||||
|
|
||||||
|
Hooks.once(CONFIG.DH.HOOKS.hooksConfig.lockedTooltipDismissed, () => {
|
||||||
|
resourceManager.classList.toggle('inverted');
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const element of html.querySelectorAll('.resource-value'))
|
||||||
|
element.addEventListener('click', this.onUpdateResource.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
async onUpdateResource(event) {
|
||||||
|
const target = event.target.closest('.resource-value');
|
||||||
|
const { resource, value: textValue } = target.dataset;
|
||||||
|
|
||||||
|
const inputValue = Number.parseInt(textValue);
|
||||||
|
const decreasing = inputValue <= this.document.system.resources[resource].value;
|
||||||
|
const value = decreasing ? inputValue - 1 : inputValue;
|
||||||
|
await this.document.update({ [`system.resources.${resource}.value`]: value }, { render: false });
|
||||||
|
|
||||||
|
/* Update resource symbols */
|
||||||
|
const section = target.closest('.resource-section');
|
||||||
|
for (const element of section.querySelectorAll('.resource-value')) {
|
||||||
|
const showFull = Number.parseInt(element.dataset.value) <= value;
|
||||||
|
element.querySelector('.full').classList.toggle('hidden', !showFull);
|
||||||
|
element.querySelector('.empty').classList.toggle('hidden', showFull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the downtime application.
|
* Open the downtime application.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,32 @@ export default class DHBaseActorSettings extends DHApplicationMixin(DocumentShee
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(options);
|
||||||
context.isNPC = this.actor.isNPC;
|
context.isNPC = this.actor.isNPC;
|
||||||
|
|
||||||
if (context.systemFields.attack)
|
if (context.systemFields.attack) {
|
||||||
context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
|
context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create fake fields for actor configurable max resource value.
|
||||||
|
const resourceConfig = CONFIG.DH.RESOURCE[this.actor.type]?.all;
|
||||||
|
if (resourceConfig) {
|
||||||
|
const relevant = ['hitPoints', 'stress'].filter(r => r in resourceConfig);
|
||||||
|
context.resources = relevant.map(key => {
|
||||||
|
const data = this.actor._source.system.resources[key];
|
||||||
|
const config = resourceConfig[key];
|
||||||
|
return {
|
||||||
|
label: config.label,
|
||||||
|
name: `system.resources.${key}.max`,
|
||||||
|
value: data.max ?? config.max,
|
||||||
|
tooltip: key === 'hitPoints' ? game.i18n.localize('DAGGERHEART.UI.Tooltip.maxHPClassBound') : null,
|
||||||
|
field: new foundry.data.fields.NumberField({
|
||||||
|
initial: config.max,
|
||||||
|
integer: true,
|
||||||
|
label: game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', {
|
||||||
|
thing: game.i18n.localize(config.label)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -698,6 +698,9 @@ export default function DHApplicationMixin(Base) {
|
||||||
case 'weapon':
|
case 'weapon':
|
||||||
presets.folder = 'equipments.folders.weapons';
|
presets.folder = 'equipments.folders.weapons';
|
||||||
break;
|
break;
|
||||||
|
case 'feature':
|
||||||
|
presets.folder = 'features';
|
||||||
|
break;
|
||||||
case 'domainCard':
|
case 'domainCard':
|
||||||
presets.folder = 'domains';
|
presets.folder = 'domains';
|
||||||
presets.filter = {
|
presets.filter = {
|
||||||
|
|
|
||||||
|
|
@ -251,6 +251,12 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
|
||||||
/* If any noticeable slowdown occurs, consider replacing with enriching description on clicking to expand descriptions */
|
/* If any noticeable slowdown occurs, consider replacing with enriching description on clicking to expand descriptions */
|
||||||
for (const item of this.items) {
|
for (const item of this.items) {
|
||||||
|
if (['weapon', 'armor'].includes(item.type)) {
|
||||||
|
item.system.enrichedTags = await foundry.applications.handlebars.renderTemplate(
|
||||||
|
'systems/daggerheart/templates/sheets/global/partials/item-tags.hbs',
|
||||||
|
item.system
|
||||||
|
);
|
||||||
|
}
|
||||||
item.system.enrichedDescription =
|
item.system.enrichedDescription =
|
||||||
(await item.system.getEnrichedDescription?.()) ??
|
(await item.system.getEnrichedDescription?.()) ??
|
||||||
(await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description));
|
(await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description));
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,4 @@ export * as settingsConfig from './settingsConfig.mjs';
|
||||||
export * as systemConfig from './system.mjs';
|
export * as systemConfig from './system.mjs';
|
||||||
export * as itemBrowserConfig from './itemBrowserConfig.mjs';
|
export * as itemBrowserConfig from './itemBrowserConfig.mjs';
|
||||||
export * as triggerConfig from './triggerConfig.mjs';
|
export * as triggerConfig from './triggerConfig.mjs';
|
||||||
|
export * as resourceConfig from './resourceConfig.mjs';
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,12 @@ export const actionTypes = {
|
||||||
icon: 'fa-ghost',
|
icon: 'fa-ghost',
|
||||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.summon.tooltip'
|
tooltip: 'DAGGERHEART.ACTIONS.TYPES.summon.tooltip'
|
||||||
},
|
},
|
||||||
|
transform: {
|
||||||
|
id: 'transform',
|
||||||
|
name: 'DAGGERHEART.ACTIONS.TYPES.transform.name',
|
||||||
|
icon: 'fa-dragon',
|
||||||
|
tooltip: 'DAGGERHEART.ACTIONS.TYPES.transform.tooltip'
|
||||||
|
},
|
||||||
effect: {
|
effect: {
|
||||||
id: 'effect',
|
id: 'effect',
|
||||||
name: 'DAGGERHEART.ACTIONS.TYPES.effect.name',
|
name: 'DAGGERHEART.ACTIONS.TYPES.effect.name',
|
||||||
|
|
|
||||||
|
|
@ -55,24 +55,6 @@ export const abilities = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scrollingTextResource = {
|
|
||||||
hitPoints: {
|
|
||||||
label: 'DAGGERHEART.GENERAL.HitPoints.plural',
|
|
||||||
reversed: true
|
|
||||||
},
|
|
||||||
stress: {
|
|
||||||
label: 'DAGGERHEART.GENERAL.stress',
|
|
||||||
reversed: true
|
|
||||||
},
|
|
||||||
hope: {
|
|
||||||
label: 'DAGGERHEART.GENERAL.hope'
|
|
||||||
},
|
|
||||||
armor: {
|
|
||||||
label: 'DAGGERHEART.GENERAL.armor',
|
|
||||||
reversed: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const featureProperties = {
|
export const featureProperties = {
|
||||||
agility: {
|
agility: {
|
||||||
name: 'DAGGERHEART.CONFIG.Traits.agility.name',
|
name: 'DAGGERHEART.CONFIG.Traits.agility.name',
|
||||||
|
|
|
||||||
|
|
@ -634,7 +634,95 @@ export const diceSetNumbers = {
|
||||||
flat: 'Flat'
|
flat: 'Flat'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDiceSoNicePreset = async (type, faces) => {
|
export const diceSoNiceSFXClasses = {
|
||||||
|
PlayAnimationBright: {
|
||||||
|
id: 'PlayAnimationBright',
|
||||||
|
label: 'DICESONICE.PlayAnimationBright'
|
||||||
|
},
|
||||||
|
PlayAnimationDark: {
|
||||||
|
id: 'PlayAnimationDark',
|
||||||
|
label: 'DICESONICE.PlayAnimationDark'
|
||||||
|
},
|
||||||
|
PlayAnimationOutline: {
|
||||||
|
id: 'PlayAnimationOutline',
|
||||||
|
label: 'DICESONICE.PlayAnimationOutline'
|
||||||
|
},
|
||||||
|
PlayAnimationImpact: {
|
||||||
|
id: 'PlayAnimationImpact',
|
||||||
|
label: 'DICESONICE.PlayAnimationImpact'
|
||||||
|
},
|
||||||
|
// PlayConfettiStrength1: {
|
||||||
|
// id: 'PlayConfettiStrength1',
|
||||||
|
// label: 'DICESONICE.PlayConfettiStrength1'
|
||||||
|
// },
|
||||||
|
// PlayConfettiStrength2: {
|
||||||
|
// id: 'PlayConfettiStrength2',
|
||||||
|
// label: 'DICESONICE.PlayConfettiStrength2'
|
||||||
|
// },
|
||||||
|
// PlayConfettiStrength3: {
|
||||||
|
// id: 'PlayConfettiStrength3',
|
||||||
|
// label: 'DICESONICE.PlayConfettiStrength3'
|
||||||
|
// },
|
||||||
|
PlayAnimationThormund: {
|
||||||
|
id: 'PlayAnimationThormund',
|
||||||
|
label: 'DICESONICE.PlayAnimationThormund'
|
||||||
|
},
|
||||||
|
PlayAnimationParticleSpiral: {
|
||||||
|
id: 'PlayAnimationParticleSpiral',
|
||||||
|
label: 'DICESONICE.PlayAnimationParticleSpiral'
|
||||||
|
},
|
||||||
|
PlayAnimationParticleSparkles: {
|
||||||
|
id: 'PlayAnimationParticleSparkles',
|
||||||
|
label: 'DICESONICE.PlayAnimationParticleSparkles'
|
||||||
|
},
|
||||||
|
PlayAnimationParticleVortex: {
|
||||||
|
id: 'PlayAnimationParticleVortex',
|
||||||
|
label: 'DICESONICE.PlayAnimationParticleVortex'
|
||||||
|
},
|
||||||
|
PlaySoundEpicWin: {
|
||||||
|
id: 'PlaySoundEpicWin',
|
||||||
|
label: 'DICESONICE.PlaySoundEpicWin'
|
||||||
|
},
|
||||||
|
PlaySoundEpicFail: {
|
||||||
|
id: 'PlaySoundEpicFail',
|
||||||
|
label: 'DICESONICE.PlaySoundEpicFail'
|
||||||
|
}
|
||||||
|
// "PlaySoundCustom",
|
||||||
|
// "PlayMacro"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const daggerheartDiceAnimationEvents = {
|
||||||
|
critical: {
|
||||||
|
id: 'critical',
|
||||||
|
label: 'DAGGERHEART.CONFIG.DaggerheartDiceAnimationEvents.critical.name'
|
||||||
|
},
|
||||||
|
higher: {
|
||||||
|
id: 'higher',
|
||||||
|
label: 'DAGGERHEART.CONFIG.DaggerheartDiceAnimationEvents.higher.name'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDiceSoNiceSFX = sfxOptions => {
|
||||||
|
const diceSoNice = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).diceSoNiceData;
|
||||||
|
const criticalAnimationData = diceSoNice.sfx.critical;
|
||||||
|
if (sfxOptions.critical && criticalAnimationData.class) {
|
||||||
|
return {
|
||||||
|
specialEffect: criticalAnimationData.class,
|
||||||
|
options: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sfxOptions.higher && sfxOptions.data.higher) {
|
||||||
|
return {
|
||||||
|
specialEffect: sfxOptions.data.higher.class,
|
||||||
|
options: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getDiceSoNicePreset = async (type, faces, sfxOptions = {}) => {
|
||||||
const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces);
|
const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces);
|
||||||
if (!system) {
|
if (!system) {
|
||||||
ui.notifications.error(
|
ui.notifications.error(
|
||||||
|
|
@ -657,16 +745,33 @@ export const getDiceSoNicePreset = async (type, faces) => {
|
||||||
appearance: {
|
appearance: {
|
||||||
...system.appearance,
|
...system.appearance,
|
||||||
...type
|
...type
|
||||||
}
|
},
|
||||||
|
sfx: getDiceSoNiceSFX(sfxOptions)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => {
|
export const getDiceSoNicePresets = async (
|
||||||
const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
result,
|
||||||
|
hopeFaces,
|
||||||
|
fearFaces,
|
||||||
|
advantageFaces = 'd6',
|
||||||
|
disadvantageFaces = 'd6'
|
||||||
|
) => {
|
||||||
|
const diceSoNice = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).diceSoNiceData;
|
||||||
|
|
||||||
|
const { isCritical, withHope, withFear } = result;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces),
|
hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces, {
|
||||||
fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces),
|
critical: isCritical,
|
||||||
|
higher: withHope,
|
||||||
|
data: diceSoNice.hope.sfx
|
||||||
|
}),
|
||||||
|
fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces, {
|
||||||
|
critical: isCritical,
|
||||||
|
higher: withFear,
|
||||||
|
data: diceSoNice.fear.sfx
|
||||||
|
}),
|
||||||
advantage: await getDiceSoNicePreset(diceSoNice.advantage, advantageFaces),
|
advantage: await getDiceSoNicePreset(diceSoNice.advantage, advantageFaces),
|
||||||
disadvantage: await getDiceSoNicePreset(diceSoNice.disadvantage, disadvantageFaces)
|
disadvantage: await getDiceSoNicePreset(diceSoNice.disadvantage, disadvantageFaces)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
export const hooksConfig = {
|
export const hooksConfig = {
|
||||||
effectDisplayToggle: 'DHEffectDisplayToggle'
|
effectDisplayToggle: 'DHEffectDisplayToggle',
|
||||||
|
lockedTooltipDismissed: 'DHLockedTooltipDismissed'
|
||||||
};
|
};
|
||||||
|
|
|
||||||
88
module/config/resourceConfig.mjs
Normal file
88
module/config/resourceConfig.mjs
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
* Full custom typing:
|
||||||
|
* id
|
||||||
|
* initial
|
||||||
|
* max
|
||||||
|
* reverse
|
||||||
|
* label
|
||||||
|
* images {
|
||||||
|
* full { value, isIcon, noColorFilter }
|
||||||
|
* empty { value, isIcon noColorFilter }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
const characterBaseResources = Object.freeze({
|
||||||
|
hitPoints: {
|
||||||
|
id: 'hitPoints',
|
||||||
|
initial: 0,
|
||||||
|
max: 0,
|
||||||
|
reverse: true,
|
||||||
|
label: 'DAGGERHEART.GENERAL.HitPoints.plural',
|
||||||
|
maxLabel: 'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
||||||
|
},
|
||||||
|
stress: {
|
||||||
|
id: 'stress',
|
||||||
|
initial: 0,
|
||||||
|
max: 6,
|
||||||
|
reverse: true,
|
||||||
|
label: 'DAGGERHEART.GENERAL.stress'
|
||||||
|
},
|
||||||
|
hope: {
|
||||||
|
id: 'hope',
|
||||||
|
initial: 2,
|
||||||
|
reverse: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.hope'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const adversaryBaseResources = Object.freeze({
|
||||||
|
hitPoints: {
|
||||||
|
id: 'hitPoints',
|
||||||
|
initial: 0,
|
||||||
|
max: 0,
|
||||||
|
reverse: true,
|
||||||
|
label: 'DAGGERHEART.GENERAL.HitPoints.plural',
|
||||||
|
maxLabel: 'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
||||||
|
},
|
||||||
|
stress: {
|
||||||
|
id: 'stress',
|
||||||
|
initial: 0,
|
||||||
|
max: 0,
|
||||||
|
reverse: true,
|
||||||
|
label: 'DAGGERHEART.GENERAL.stress'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const companionBaseResources = Object.freeze({
|
||||||
|
stress: {
|
||||||
|
id: 'stress',
|
||||||
|
initial: 0,
|
||||||
|
max: 0,
|
||||||
|
reverse: true,
|
||||||
|
label: 'DAGGERHEART.GENERAL.stress'
|
||||||
|
},
|
||||||
|
hope: {
|
||||||
|
id: 'hope',
|
||||||
|
initial: 0,
|
||||||
|
reverse: false,
|
||||||
|
label: 'DAGGERHEART.GENERAL.hope'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const character = {
|
||||||
|
base: characterBaseResources,
|
||||||
|
custom: {}, // module stuff goes here
|
||||||
|
all: { ...characterBaseResources }
|
||||||
|
};
|
||||||
|
|
||||||
|
export const adversary = {
|
||||||
|
base: adversaryBaseResources,
|
||||||
|
custom: {}, // module stuff goes here
|
||||||
|
all: { ...adversaryBaseResources }
|
||||||
|
};
|
||||||
|
|
||||||
|
export const companion = {
|
||||||
|
base: companionBaseResources,
|
||||||
|
custom: {}, // module stuff goes here
|
||||||
|
all: { ...companionBaseResources }
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,10 @@ export const menu = {
|
||||||
Name: 'GameSettingsAutomation',
|
Name: 'GameSettingsAutomation',
|
||||||
Icon: 'fa-solid fa-robot'
|
Icon: 'fa-solid fa-robot'
|
||||||
},
|
},
|
||||||
|
Metagaming: {
|
||||||
|
Name: 'GameSettingsMetagaming',
|
||||||
|
Icon: 'fa-solid fa-eye-low-vision'
|
||||||
|
},
|
||||||
Homebrew: {
|
Homebrew: {
|
||||||
Name: 'GameSettingsHomebrew',
|
Name: 'GameSettingsHomebrew',
|
||||||
Icon: 'fa-solid fa-flask-vial'
|
Icon: 'fa-solid fa-flask-vial'
|
||||||
|
|
@ -19,8 +23,10 @@ export const menu = {
|
||||||
|
|
||||||
export const gameSettings = {
|
export const gameSettings = {
|
||||||
Automation: 'Automation',
|
Automation: 'Automation',
|
||||||
|
Metagaming: 'Metagaming',
|
||||||
Homebrew: 'Homebrew',
|
Homebrew: 'Homebrew',
|
||||||
appearance: 'Appearance',
|
appearance: 'Appearance',
|
||||||
|
GlobalOverrides: 'GlobalOverrides',
|
||||||
variantRules: 'VariantRules',
|
variantRules: 'VariantRules',
|
||||||
Resources: {
|
Resources: {
|
||||||
Fear: 'ResourcesFear'
|
Fear: 'ResourcesFear'
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import * as GENERAL from './generalConfig.mjs';
|
||||||
import * as DOMAIN from './domainConfig.mjs';
|
import * as DOMAIN from './domainConfig.mjs';
|
||||||
import * as ENCOUNTER from './encounterConfig.mjs';
|
import * as ENCOUNTER from './encounterConfig.mjs';
|
||||||
import * as ACTOR from './actorConfig.mjs';
|
import * as ACTOR from './actorConfig.mjs';
|
||||||
|
import * as RESOURCE from './resourceConfig.mjs';
|
||||||
import * as ITEM from './itemConfig.mjs';
|
import * as ITEM from './itemConfig.mjs';
|
||||||
import * as SETTINGS from './settingsConfig.mjs';
|
import * as SETTINGS from './settingsConfig.mjs';
|
||||||
import * as EFFECTS from './effectConfig.mjs';
|
import * as EFFECTS from './effectConfig.mjs';
|
||||||
|
|
@ -19,6 +20,7 @@ export const SYSTEM = {
|
||||||
GENERAL,
|
GENERAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ACTOR,
|
ACTOR,
|
||||||
|
RESOURCE,
|
||||||
ITEM,
|
ITEM,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
EFFECTS,
|
EFFECTS,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import EffectAction from './effectAction.mjs';
|
||||||
import HealingAction from './healingAction.mjs';
|
import HealingAction from './healingAction.mjs';
|
||||||
import MacroAction from './macroAction.mjs';
|
import MacroAction from './macroAction.mjs';
|
||||||
import SummonAction from './summonAction.mjs';
|
import SummonAction from './summonAction.mjs';
|
||||||
|
import TransformAction from './transformAction.mjs';
|
||||||
|
|
||||||
export const actionsTypes = {
|
export const actionsTypes = {
|
||||||
base: BaseAction,
|
base: BaseAction,
|
||||||
|
|
@ -17,5 +18,6 @@ export const actionsTypes = {
|
||||||
summon: SummonAction,
|
summon: SummonAction,
|
||||||
effect: EffectAction,
|
effect: EffectAction,
|
||||||
macro: MacroAction,
|
macro: MacroAction,
|
||||||
beastform: BeastformAction
|
beastform: BeastformAction,
|
||||||
|
transform: TransformAction
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
async executeWorkflow(config) {
|
async executeWorkflow(config) {
|
||||||
for (const [key, part] of this.workflow) {
|
for (const [key, part] of this.workflow) {
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.pre${key.capitalize()}Action`, this, config) === false) return;
|
if (Hooks.call(`${CONFIG.DH.id}.pre${key.capitalize()}Action`, this, config) === false) return;
|
||||||
if ((await part.execute(config)) === false) return;
|
if ((await part.execute(config)) === false) return false;
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.post${key.capitalize()}Action`, this, config) === false) return;
|
if (Hooks.call(`${CONFIG.DH.id}.post${key.capitalize()}Action`, this, config) === false) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the Action Worflow in order based of schema fields
|
// Execute the Action Worflow in order based of schema fields
|
||||||
await this.executeWorkflow(config);
|
const result = await this.executeWorkflow(config);
|
||||||
|
if (result === false) return;
|
||||||
|
|
||||||
await config.resourceUpdates.updateResources();
|
await config.resourceUpdates.updateResources();
|
||||||
|
|
||||||
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
||||||
|
|
|
||||||
5
module/data/action/transformAction.mjs
Normal file
5
module/data/action/transformAction.mjs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import DHBaseAction from './baseAction.mjs';
|
||||||
|
|
||||||
|
export default class DHTransformAction extends DHBaseAction {
|
||||||
|
static extraSchemas = [...super.extraSchemas, 'transform'];
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import DHAdversarySettings from '../../applications/sheets-configs/adversary-set
|
||||||
import { ActionField } from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import { commonActorRules } from './base.mjs';
|
import { commonActorRules } from './base.mjs';
|
||||||
import DhCreature from './creature.mjs';
|
import DhCreature from './creature.mjs';
|
||||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
import { bonusField } from '../fields/actorField.mjs';
|
||||||
import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs';
|
import { calculateExpectedValue, parseTermsFromSimpleFormula } from '../../helpers/utils.mjs';
|
||||||
import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs';
|
import { adversaryExpectedDamage, adversaryScalingData } from '../../config/actorConfig.mjs';
|
||||||
|
|
||||||
|
|
@ -65,10 +65,6 @@ export default class DhpAdversary extends DhCreature {
|
||||||
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
label: 'DAGGERHEART.GENERAL.DamageThresholds.severeThreshold'
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
resources: new fields.SchemaField({
|
|
||||||
hitPoints: resourceField(0, 0, 'DAGGERHEART.GENERAL.HitPoints.plural', true),
|
|
||||||
stress: resourceField(0, 0, 'DAGGERHEART.GENERAL.stress', true)
|
|
||||||
}),
|
|
||||||
rules: new fields.SchemaField({
|
rules: new fields.SchemaField({
|
||||||
...commonActorRules()
|
...commonActorRules()
|
||||||
}),
|
}),
|
||||||
|
|
@ -191,6 +187,7 @@ export default class DhpAdversary extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
|
super.prepareDerivedData();
|
||||||
this.attack.roll.isStandardAttack = true;
|
this.attack.roll.isStandardAttack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
||||||
const textData = Object.keys(changes.system.resources).reduce((acc, key) => {
|
const textData = Object.keys(changes.system.resources).reduce((acc, key) => {
|
||||||
const resource = changes.system.resources[key];
|
const resource = changes.system.resources[key];
|
||||||
if (resource.value !== undefined && resource.value !== this.resources[key].value) {
|
if (resource.value !== undefined && resource.value !== this.resources[key].value) {
|
||||||
acc.push(getScrollTextData(this.resources, resource, key));
|
acc.push(getScrollTextData(this.parent, resource, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import DhLevelData from '../levelData.mjs';
|
import DhLevelData from '../levelData.mjs';
|
||||||
import { commonActorRules } from './base.mjs';
|
import { commonActorRules } from './base.mjs';
|
||||||
import DhCreature from './creature.mjs';
|
import DhCreature from './creature.mjs';
|
||||||
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
import { attributeField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||||
import { ActionField } from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
|
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
|
||||||
|
|
||||||
|
|
@ -27,28 +27,6 @@ export default class DhCharacter extends DhCreature {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
resources: new fields.SchemaField({
|
|
||||||
hitPoints: resourceField(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'DAGGERHEART.GENERAL.HitPoints.plural',
|
|
||||||
true,
|
|
||||||
'DAGGERHEART.ACTORS.Character.maxHPBonus'
|
|
||||||
),
|
|
||||||
stress: resourceField(6, 0, 'DAGGERHEART.GENERAL.stress', true),
|
|
||||||
hope: new fields.SchemaField(
|
|
||||||
{
|
|
||||||
value: new fields.NumberField({
|
|
||||||
initial: 2,
|
|
||||||
min: 0,
|
|
||||||
integer: true,
|
|
||||||
label: 'DAGGERHEART.GENERAL.hope'
|
|
||||||
}),
|
|
||||||
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'),
|
||||||
strength: attributeField('DAGGERHEART.CONFIG.Traits.strength.name'),
|
strength: attributeField('DAGGERHEART.CONFIG.Traits.strength.name'),
|
||||||
|
|
@ -609,6 +587,7 @@ export default class DhCharacter extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareBaseData() {
|
prepareBaseData() {
|
||||||
|
super.prepareBaseData();
|
||||||
this.evasion += this.class.value?.system?.evasion ?? 0;
|
this.evasion += this.class.value?.system?.evasion ?? 0;
|
||||||
|
|
||||||
const currentLevel = this.levelData.level.current;
|
const currentLevel = this.levelData.level.current;
|
||||||
|
|
@ -680,6 +659,7 @@ export default class DhCharacter extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
|
super.prepareDerivedData();
|
||||||
let baseHope = this.resources.hope.value;
|
let baseHope = this.resources.hope.value;
|
||||||
if (this.companion) {
|
if (this.companion) {
|
||||||
for (let levelKey in this.companion.system.levelData.levelups) {
|
for (let levelKey in this.companion.system.levelData.levelups) {
|
||||||
|
|
@ -699,6 +679,7 @@ export default class DhCharacter extends DhCreature {
|
||||||
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
this.attack.roll.trait = this.rules.attack.roll.trait ?? this.attack.roll.trait;
|
||||||
|
|
||||||
this.resources.armor = {
|
this.resources.armor = {
|
||||||
|
label: 'DAGGERHEART.GENERAL.armor',
|
||||||
value: this.armor?.system?.marks?.value ?? 0,
|
value: this.armor?.system?.marks?.value ?? 0,
|
||||||
max: this.armorScore,
|
max: this.armorScore,
|
||||||
isReversed: true
|
isReversed: true
|
||||||
|
|
@ -740,7 +721,8 @@ export default class DhCharacter extends DhCreature {
|
||||||
const newHopeMax = this.system.resources.hope.max + diff;
|
const newHopeMax = this.system.resources.hope.max + diff;
|
||||||
const newHopeValue = Math.min(newHopeMax, this.system.resources.hope.value);
|
const newHopeValue = Math.min(newHopeMax, this.system.resources.hope.value);
|
||||||
if (newHopeValue != this.system.resources.hope.value) {
|
if (newHopeValue != this.system.resources.hope.value) {
|
||||||
if (!changes.system.resources) changes.system.resources = { hope: { value: 0 } };
|
if (!changes.system.resources.hope) changes.system.resources.hope = { value: 0 };
|
||||||
|
|
||||||
changes.system.resources.hope = {
|
changes.system.resources.hope = {
|
||||||
...changes.system.resources.hope,
|
...changes.system.resources.hope,
|
||||||
value: changes.system.resources.hope.value + newHopeValue
|
value: changes.system.resources.hope.value + newHopeValue
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import { ActionField } from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
||||||
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
|
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
|
||||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
import { bonusField } from '../fields/actorField.mjs';
|
||||||
|
|
||||||
export default class DhCompanion extends DhCreature {
|
export default class DhCompanion extends DhCreature {
|
||||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Companion'];
|
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Companion'];
|
||||||
|
|
@ -26,10 +26,6 @@ export default class DhCompanion extends DhCreature {
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
|
partner: new ForeignDocumentUUIDField({ type: 'Actor' }),
|
||||||
resources: new fields.SchemaField({
|
|
||||||
stress: resourceField(3, 0, 'DAGGERHEART.GENERAL.stress', true),
|
|
||||||
hope: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.hope' })
|
|
||||||
}),
|
|
||||||
evasion: new fields.NumberField({
|
evasion: new fields.NumberField({
|
||||||
required: true,
|
required: true,
|
||||||
min: 1,
|
min: 1,
|
||||||
|
|
@ -127,6 +123,7 @@ export default class DhCompanion extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareBaseData() {
|
prepareBaseData() {
|
||||||
|
super.prepareBaseData();
|
||||||
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
this.attack.roll.bonus = this.partner?.system?.spellcastModifier ?? 0;
|
||||||
|
|
||||||
for (let levelKey in this.levelData.levelups) {
|
for (let levelKey in this.levelData.levelups) {
|
||||||
|
|
@ -163,6 +160,7 @@ export default class DhCompanion extends DhCreature {
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
|
super.prepareDerivedData();
|
||||||
/* Partner Related Setup */
|
/* Partner Related Setup */
|
||||||
if (this.partner) {
|
if (this.partner) {
|
||||||
this.levelData.level.changed = this.partner.system.levelData.level.current;
|
this.levelData.level.changed = this.partner.system.levelData.level.current;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { ResourcesField } from '../fields/actorField.mjs';
|
||||||
import BaseDataActor from './base.mjs';
|
import BaseDataActor from './base.mjs';
|
||||||
|
|
||||||
export default class DhCreature extends BaseDataActor {
|
export default class DhCreature extends BaseDataActor {
|
||||||
|
|
@ -7,6 +8,7 @@ export default class DhCreature extends BaseDataActor {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...super.defineSchema(),
|
...super.defineSchema(),
|
||||||
|
resources: new ResourcesField(this.metadata.type),
|
||||||
advantageSources: new fields.ArrayField(new fields.StringField(), {
|
advantageSources: new fields.ArrayField(new fields.StringField(), {
|
||||||
label: 'DAGGERHEART.ACTORS.Character.advantageSources.label',
|
label: 'DAGGERHEART.ACTORS.Character.advantageSources.label',
|
||||||
hint: 'DAGGERHEART.ACTORS.Character.advantageSources.hint'
|
hint: 'DAGGERHEART.ACTORS.Character.advantageSources.hint'
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,4 @@ export { default as DamageField } from './damageField.mjs';
|
||||||
export { default as RollField } from './rollField.mjs';
|
export { default as RollField } from './rollField.mjs';
|
||||||
export { default as MacroField } from './macroField.mjs';
|
export { default as MacroField } from './macroField.mjs';
|
||||||
export { default as SummonField } from './summonField.mjs';
|
export { default as SummonField } from './summonField.mjs';
|
||||||
|
export { default as TransformField } from './transformField.mjs';
|
||||||
|
|
|
||||||
103
module/data/fields/action/transformField.mjs
Normal file
103
module/data/fields/action/transformField.mjs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
export default class DHSummonField extends fields.SchemaField {
|
||||||
|
/**
|
||||||
|
* Action Workflow order
|
||||||
|
*/
|
||||||
|
static order = 130;
|
||||||
|
|
||||||
|
constructor(options = {}, context = {}) {
|
||||||
|
const transformFields = {
|
||||||
|
actorUUID: new fields.DocumentUUIDField({
|
||||||
|
type: 'Actor',
|
||||||
|
required: true
|
||||||
|
}),
|
||||||
|
resourceRefresh: new fields.SchemaField({
|
||||||
|
hitPoints: new fields.BooleanField({ initial: true }),
|
||||||
|
stress: new fields.BooleanField({ initial: true })
|
||||||
|
})
|
||||||
|
};
|
||||||
|
super(transformFields, options, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async execute() {
|
||||||
|
if (!this.transform.actorUUID) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.transform.noTransformActor'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseActor = await foundry.utils.fromUuid(this.transform.actorUUID);
|
||||||
|
if (!baseActor) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.transform.transformActorMissing'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canvas.scene) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.transform.canvasError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.actor.prototypeToken.actorLink) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.transform.actorLinkError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.actor.token) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.transform.prototypeError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actor = await DHSummonField.getWorldActor(baseActor);
|
||||||
|
const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes;
|
||||||
|
const tokenSize = actor?.system.metadata.usesSize ? tokenSizes[actor.system.size] : actor.prototypeToken.width;
|
||||||
|
|
||||||
|
await this.actor.token.update(
|
||||||
|
{ ...actor.prototypeToken.toJSON(), actorId: actor.id, width: tokenSize, height: tokenSize },
|
||||||
|
{ diff: false, recursive: false, noHook: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.actor.token.combatant) {
|
||||||
|
this.actor.token.combatant.update({ actorId: actor.id, img: actor.prototypeToken.texture.src });
|
||||||
|
}
|
||||||
|
|
||||||
|
const marks = { hitPoints: 0, stress: 0 };
|
||||||
|
if (!this.transform.resourceRefresh.hitPoints) {
|
||||||
|
marks.hitPoints = Math.min(
|
||||||
|
this.actor.system.resources.hitPoints.value,
|
||||||
|
this.actor.token.actor.system.resources.hitPoints.max - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!this.transform.resourceRefresh.stress) {
|
||||||
|
marks.stress = Math.min(
|
||||||
|
this.actor.system.resources.stress.value,
|
||||||
|
this.actor.token.actor.system.resources.stress.max - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (marks.hitPoints || marks.stress) {
|
||||||
|
this.actor.token.actor.update({
|
||||||
|
'system.resources': {
|
||||||
|
hitPoints: { value: marks.hitPoints },
|
||||||
|
stress: { value: marks.stress }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const prevPosition = { ...this.actor.sheet.position };
|
||||||
|
this.actor.sheet.close();
|
||||||
|
this.actor.token.actor.sheet.render({ force: true, position: prevPosition });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for any available instances of the actor present in the world, or create a world actor based on compendium */
|
||||||
|
static async getWorldActor(baseActor) {
|
||||||
|
if (!baseActor.inCompendium) return baseActor;
|
||||||
|
|
||||||
|
const dataType = game.system.api.data.actors[`Dh${baseActor.type.capitalize()}`];
|
||||||
|
if (dataType && baseActor.img === dataType.DEFAULT_ICON) {
|
||||||
|
const worldActorCopy = game.actors.find(x => x.name === baseActor.name);
|
||||||
|
if (worldActorCopy) return worldActorCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
const worldActor = await game.system.api.documents.DhpActor.create(baseActor.toObject());
|
||||||
|
return worldActor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,22 +6,6 @@ const attributeField = label =>
|
||||||
tierMarked: new fields.BooleanField({ initial: false })
|
tierMarked: new fields.BooleanField({ initial: false })
|
||||||
});
|
});
|
||||||
|
|
||||||
const resourceField = (max = 0, initial = 0, label, reverse = false, maxLabel) =>
|
|
||||||
new fields.SchemaField(
|
|
||||||
{
|
|
||||||
value: new fields.NumberField({ initial: initial, min: 0, integer: true, label }),
|
|
||||||
max: new fields.NumberField({
|
|
||||||
initial: max,
|
|
||||||
integer: true,
|
|
||||||
label:
|
|
||||||
maxLabel ??
|
|
||||||
game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
|
|
||||||
}),
|
|
||||||
isReversed: new fields.BooleanField({ initial: reverse })
|
|
||||||
},
|
|
||||||
{ label }
|
|
||||||
);
|
|
||||||
|
|
||||||
const stressDamageReductionRule = localizationPath =>
|
const stressDamageReductionRule = localizationPath =>
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
cost: new fields.NumberField({
|
cost: new fields.NumberField({
|
||||||
|
|
@ -37,4 +21,67 @@ const bonusField = label =>
|
||||||
dice: new fields.ArrayField(new fields.StringField(), { label: `${game.i18n.localize(label)} Dice` })
|
dice: new fields.ArrayField(new fields.StringField(), { label: `${game.i18n.localize(label)} Dice` })
|
||||||
});
|
});
|
||||||
|
|
||||||
export { attributeField, resourceField, stressDamageReductionRule, bonusField };
|
/**
|
||||||
|
* Field used for actor resources. It is a resource that validates dynamically based on the config.
|
||||||
|
* Because "max" may be defined during runtime, we don't attempt to clamp the maximum value.
|
||||||
|
*/
|
||||||
|
class ResourcesField extends fields.TypedObjectField {
|
||||||
|
constructor(actorType) {
|
||||||
|
super(
|
||||||
|
new fields.SchemaField({
|
||||||
|
value: new fields.NumberField({ min: 0, initial: 0, integer: true }),
|
||||||
|
// Some resources allow changing max. A null max means its the default
|
||||||
|
max: new fields.NumberField({ initial: null, integer: true, nullable: true })
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.actorType = actorType;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInitialValue() {
|
||||||
|
const resources = CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
return Object.values(resources).reduce((result, resource) => {
|
||||||
|
result[resource.id] = {
|
||||||
|
value: resource.initial,
|
||||||
|
max: null
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
_validateKey(key) {
|
||||||
|
return key in CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanType(value, options) {
|
||||||
|
value = super._cleanType(value, options);
|
||||||
|
|
||||||
|
// If not partial, ensure all data exists
|
||||||
|
if (!options.partial) {
|
||||||
|
value = foundry.utils.mergeObject(this.getInitialValue(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Initializes the original source data, returning prepared data */
|
||||||
|
initialize(...args) {
|
||||||
|
const data = super.initialize(...args);
|
||||||
|
const resources = CONFIG.DH.RESOURCE[this.actorType].all;
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
// TypedObjectField only calls _validateKey when persisting, so we also call it here
|
||||||
|
if (!this._validateKey(key)) {
|
||||||
|
delete value[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add basic prepared data.
|
||||||
|
const resource = resources[key];
|
||||||
|
value.label = resource.label;
|
||||||
|
value.isReversed = resources[key].reverse;
|
||||||
|
value.max = typeof resource.max === 'number' ? (value.max ?? resource.max) : null;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { attributeField, ResourcesField, stressDamageReductionRule, bonusField };
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
const armorChanged =
|
const armorChanged =
|
||||||
changed.system?.marks?.value !== undefined && changed.system.marks.value !== this.marks.value;
|
changed.system?.marks?.value !== undefined && changed.system.marks.value !== this.marks.value;
|
||||||
if (armorChanged && autoSettings.resourceScrollTexts && this.parent.parent?.type === 'character') {
|
if (armorChanged && autoSettings.resourceScrollTexts && this.parent.parent?.type === 'character') {
|
||||||
const armorData = getScrollTextData(this.parent.parent.system.resources, changed.system.marks, 'armor');
|
const armorData = getScrollTextData(this.parent.parent, changed.system.marks, 'armor');
|
||||||
options.scrollingTextData = [armorData];
|
options.scrollingTextData = [armorData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,24 +112,14 @@ export default class DHWeapon extends AttachableItem {
|
||||||
async getDescriptionData() {
|
async getDescriptionData() {
|
||||||
const baseDescription = this.description;
|
const baseDescription = this.description;
|
||||||
|
|
||||||
const tier = game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${this.tier}`);
|
|
||||||
const trait = game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.attack.roll.trait].label);
|
|
||||||
const range = game.i18n.localize(`DAGGERHEART.CONFIG.Range.${this.attack.range}.name`);
|
|
||||||
const damage = Roll.replaceFormulaData(this.attack.damageFormula, this.parent.parent ?? this.parent);
|
|
||||||
const burden = game.i18n.localize(CONFIG.DH.GENERAL.burden[this.burden].label);
|
|
||||||
|
|
||||||
const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures();
|
const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures();
|
||||||
const features = this.weaponFeatures.map(x => allFeatures[x.value]).filter(x => x);
|
const features = this.weaponFeatures.map(x => allFeatures[x.value]).filter(x => x);
|
||||||
|
|
||||||
const prefix = await foundry.applications.handlebars.renderTemplate(
|
const prefix = await foundry.applications.handlebars.renderTemplate(
|
||||||
'systems/daggerheart/templates/sheets/items/weapon/description.hbs',
|
'systems/daggerheart/templates/sheets/items/weapon/description.hbs',
|
||||||
{
|
{
|
||||||
features,
|
item: this,
|
||||||
tier,
|
features
|
||||||
trait,
|
|
||||||
range,
|
|
||||||
damage,
|
|
||||||
burden
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,16 @@
|
||||||
export default class DhAppearance extends foundry.abstract.DataModel {
|
export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Appearance'];
|
static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Appearance'];
|
||||||
|
|
||||||
|
static sfxSchema = () =>
|
||||||
|
new foundry.data.fields.SchemaField({
|
||||||
|
class: new foundry.data.fields.StringField({
|
||||||
|
nullable: true,
|
||||||
|
initial: null,
|
||||||
|
blank: true,
|
||||||
|
choices: CONFIG.DH.GENERAL.diceSoNiceSFXClasses
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const { StringField, ColorField, BooleanField, SchemaField } = foundry.data.fields;
|
const { StringField, ColorField, BooleanField, SchemaField } = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -15,7 +25,10 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
colorset: new StringField({ initial: 'inspired', required: true, blank: false }),
|
colorset: new StringField({ initial: 'inspired', required: true, blank: false }),
|
||||||
material: new StringField({ initial: 'metal', required: true, blank: false }),
|
material: new StringField({ initial: 'metal', required: true, blank: false }),
|
||||||
system: new StringField({ initial: 'standard', required: true, blank: false }),
|
system: new StringField({ initial: 'standard', required: true, blank: false }),
|
||||||
font: new StringField({ initial: 'auto', required: true, blank: false })
|
font: new StringField({ initial: 'auto', required: true, blank: false }),
|
||||||
|
sfx: new SchemaField({
|
||||||
|
higher: DhAppearance.sfxSchema()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -30,7 +43,10 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
hope: diceStyle({ fg: '#ffffff', bg: '#ffe760', outline: '#000000', edge: '#ffffff' }),
|
hope: diceStyle({ fg: '#ffffff', bg: '#ffe760', outline: '#000000', edge: '#ffffff' }),
|
||||||
fear: diceStyle({ fg: '#000000', bg: '#0032b1', outline: '#ffffff', edge: '#000000' }),
|
fear: diceStyle({ fg: '#000000', bg: '#0032b1', outline: '#ffffff', edge: '#000000' }),
|
||||||
advantage: diceStyle({ fg: '#ffffff', bg: '#008000', outline: '#000000', edge: '#ffffff' }),
|
advantage: diceStyle({ fg: '#ffffff', bg: '#008000', outline: '#000000', edge: '#ffffff' }),
|
||||||
disadvantage: diceStyle({ fg: '#000000', bg: '#b30000', outline: '#ffffff', edge: '#000000' })
|
disadvantage: diceStyle({ fg: '#000000', bg: '#b30000', outline: '#ffffff', edge: '#000000' }),
|
||||||
|
sfx: new SchemaField({
|
||||||
|
critical: DhAppearance.sfxSchema()
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
extendCharacterDescriptions: new BooleanField(),
|
extendCharacterDescriptions: new BooleanField(),
|
||||||
extendAdversaryDescriptions: new BooleanField(),
|
extendAdversaryDescriptions: new BooleanField(),
|
||||||
|
|
@ -65,4 +81,48 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
||||||
showGenericStatusEffects: new BooleanField({ initial: true })
|
showGenericStatusEffects: new BooleanField({ initial: true })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get diceSoNiceData() {
|
||||||
|
const globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides);
|
||||||
|
const getSFX = (baseClientData, overrideKey) => {
|
||||||
|
if (!globalOverrides.diceSoNice.sfx.overrideEnabled) return baseClientData;
|
||||||
|
const overrideData = globalOverrides.diceSoNice.sfx[overrideKey];
|
||||||
|
const clientData = foundry.utils.deepClone(baseClientData);
|
||||||
|
return Object.keys(clientData).reduce((acc, key) => {
|
||||||
|
const data = clientData[key];
|
||||||
|
acc[key] = Object.keys(data).reduce((acc, dataKey) => {
|
||||||
|
const value = data[dataKey];
|
||||||
|
acc[dataKey] = value ? value : overrideData[key][dataKey];
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...this.diceSoNice,
|
||||||
|
sfx: getSFX(this.diceSoNice.sfx, 'global'),
|
||||||
|
hope: {
|
||||||
|
...this.diceSoNice.hope,
|
||||||
|
sfx: getSFX(this.diceSoNice.hope.sfx, 'hope')
|
||||||
|
},
|
||||||
|
fear: {
|
||||||
|
...this.diceSoNice.fear,
|
||||||
|
sfx: getSFX(this.diceSoNice.fear.sfx, 'fear')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invoked by the setting when data changes */
|
||||||
|
handleChange() {
|
||||||
|
if (this.displayFear) {
|
||||||
|
if (ui.resources) {
|
||||||
|
if (this.displayFear === 'hide') ui.resources.close({ allowed: true });
|
||||||
|
else ui.resources.render({ force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides);
|
||||||
|
globalOverrides.diceSoNiceSFXUpdate(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
module/data/settings/GlobalOverrides.mjs
Normal file
55
module/data/settings/GlobalOverrides.mjs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import DhAppearance from './Appearance.mjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A setting to handle cases where we want to allow the GM to set a global default for client settings.
|
||||||
|
*/
|
||||||
|
export default class DhGlobalOverrides extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
diceSoNice: new fields.SchemaField({
|
||||||
|
sfx: new fields.SchemaField({
|
||||||
|
overrideEnabled: new fields.BooleanField(),
|
||||||
|
global: new fields.SchemaField({
|
||||||
|
critical: DhAppearance.sfxSchema()
|
||||||
|
}),
|
||||||
|
hope: new fields.SchemaField({
|
||||||
|
higher: DhAppearance.sfxSchema()
|
||||||
|
}),
|
||||||
|
fear: new fields.SchemaField({
|
||||||
|
higher: DhAppearance.sfxSchema()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async diceSoNiceSFXUpdate(appearanceSettings, enabled) {
|
||||||
|
if (!game.user.isGM) return;
|
||||||
|
|
||||||
|
const newEnabled = enabled !== undefined ? enabled : this.diceSoNice.sfx.overrideEnabled;
|
||||||
|
if (newEnabled) {
|
||||||
|
const newOverrides = foundry.utils.mergeObject(this.toObject(), {
|
||||||
|
diceSoNice: {
|
||||||
|
sfx: {
|
||||||
|
overrideEnabled: true,
|
||||||
|
global: appearanceSettings.diceSoNice.sfx,
|
||||||
|
hope: appearanceSettings.diceSoNice.hope.sfx,
|
||||||
|
fear: appearanceSettings.diceSoNice.fear.sfx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, newOverrides);
|
||||||
|
} else {
|
||||||
|
const newOverrides = {
|
||||||
|
...this.toObject(),
|
||||||
|
diceSoNice: {
|
||||||
|
sfx: {
|
||||||
|
overrideEnabled: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, newOverrides);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -145,6 +145,16 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
description: new fields.StringField()
|
description: new fields.StringField()
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
resources: new fields.TypedObjectField(
|
||||||
|
new fields.SchemaField({
|
||||||
|
resources: new fields.TypedObjectField(new fields.EmbeddedDataField(Resource))
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
initial: {
|
||||||
|
character: { resources: {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
itemFeatures: new fields.SchemaField({
|
itemFeatures: new fields.SchemaField({
|
||||||
weaponFeatures: new fields.TypedObjectField(
|
weaponFeatures: new fields.TypedObjectField(
|
||||||
new fields.SchemaField({
|
new fields.SchemaField({
|
||||||
|
|
@ -185,4 +195,117 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Invoked by the setting when data changes */
|
||||||
|
handleChange() {
|
||||||
|
if (this.maxFear) {
|
||||||
|
if (ui.resources) ui.resources.render({ force: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.refreshConfig();
|
||||||
|
this.#resetActors();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update config values based on homebrew data. Make sure the references don't change */
|
||||||
|
refreshConfig() {
|
||||||
|
for (const [actorType, actorData] of Object.entries(this.resources)) {
|
||||||
|
const config = CONFIG.DH.RESOURCE[actorType];
|
||||||
|
for (const key of Object.keys(config.all)) {
|
||||||
|
delete config.all[key];
|
||||||
|
}
|
||||||
|
Object.assign(config.all, {
|
||||||
|
...Object.entries(actorData.resources).reduce((result, [key, value]) => {
|
||||||
|
result[key] = value.toObject();
|
||||||
|
result[key].id = key;
|
||||||
|
return result;
|
||||||
|
}, {}),
|
||||||
|
...config.custom,
|
||||||
|
...config.base
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a reset and non-forced re-render on all given actors (if given)
|
||||||
|
* or all world actors and actors in all scenes to show immediate results for a changed setting.
|
||||||
|
*/
|
||||||
|
#resetActors() {
|
||||||
|
const actors = new Set(
|
||||||
|
[
|
||||||
|
game.actors.contents,
|
||||||
|
game.scenes.contents.flatMap(s => s.tokens.contents).flatMap(t => t.actor ?? [])
|
||||||
|
].flat()
|
||||||
|
);
|
||||||
|
for (const actor of actors) {
|
||||||
|
for (const app of Object.values(actor.apps)) {
|
||||||
|
for (const element of app.element?.querySelectorAll('prose-mirror.active')) {
|
||||||
|
element.open = false; // This triggers a save
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actor.reset();
|
||||||
|
actor.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Resource extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
initial: new fields.NumberField({
|
||||||
|
required: true,
|
||||||
|
integer: true,
|
||||||
|
initial: 0,
|
||||||
|
min: 0,
|
||||||
|
label: 'DAGGERHEART.GENERAL.initial'
|
||||||
|
}),
|
||||||
|
max: new fields.NumberField({
|
||||||
|
nullable: true,
|
||||||
|
initial: null,
|
||||||
|
min: 0,
|
||||||
|
label: 'DAGGERHEART.GENERAL.max'
|
||||||
|
}),
|
||||||
|
label: new fields.StringField({ label: 'DAGGERHEART.GENERAL.label' }),
|
||||||
|
images: new fields.SchemaField({
|
||||||
|
full: imageIconField('fa solid fa-circle'),
|
||||||
|
empty: imageIconField('fa-regular fa-circle')
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaultResourceData = label => {
|
||||||
|
const images = Resource.schema.fields.images.getInitialValue();
|
||||||
|
return {
|
||||||
|
initial: 0,
|
||||||
|
max: 0,
|
||||||
|
label: label ?? '',
|
||||||
|
images
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDefaultImageData = imageKey => {
|
||||||
|
return Resource.schema.fields.images.fields[imageKey].getInitialValue();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageIconField = defaultValue =>
|
||||||
|
new foundry.data.fields.SchemaField(
|
||||||
|
{
|
||||||
|
value: new foundry.data.fields.StringField({
|
||||||
|
initial: defaultValue,
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.resources.resources.value.label'
|
||||||
|
}),
|
||||||
|
isIcon: new foundry.data.fields.BooleanField({
|
||||||
|
required: true,
|
||||||
|
initial: true,
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.resources.resources.isIcon.label'
|
||||||
|
}),
|
||||||
|
noColorFilter: new foundry.data.fields.BooleanField({
|
||||||
|
required: true,
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.resources.resources.noColorFilter.label'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ required: true }
|
||||||
|
);
|
||||||
|
|
|
||||||
12
module/data/settings/Metagaming.mjs
Normal file
12
module/data/settings/Metagaming.mjs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
export default class DhMetagaming extends foundry.abstract.DataModel {
|
||||||
|
static defineSchema() {
|
||||||
|
const fields = foundry.data.fields;
|
||||||
|
return {
|
||||||
|
hideObserverPermissionInChat: new fields.BooleanField({
|
||||||
|
initial: false,
|
||||||
|
label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.label',
|
||||||
|
hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.hint'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
export { default as DhAppearance } from './Appearance.mjs';
|
export { default as DhAppearance } from './Appearance.mjs';
|
||||||
export { default as DhAutomation } from './Automation.mjs';
|
export { default as DhAutomation } from './Automation.mjs';
|
||||||
export { default as DhHomebrew } from './Homebrew.mjs';
|
export { default as DhHomebrew } from './Homebrew.mjs';
|
||||||
|
export { default as DhMetagaming } from './Metagaming.mjs';
|
||||||
export { default as DhVariantRules } from './VariantRules.mjs';
|
export { default as DhVariantRules } from './VariantRules.mjs';
|
||||||
|
export { default as DhGlobalOverrides } from './GlobalOverrides.mjs';
|
||||||
|
|
|
||||||
|
|
@ -140,8 +140,10 @@ export default class DHRoll extends Roll {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
async render({ flavor, template = this.constructor.CHAT_TEMPLATE, isPrivate = false, ...options } = {}) {
|
async render({ flavor, template = this.constructor.CHAT_TEMPLATE, isPrivate = false, ...options } = {}) {
|
||||||
if (!this._evaluated) return;
|
if (!this._evaluated) return;
|
||||||
|
|
||||||
|
const metagamingSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming);
|
||||||
const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options });
|
const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options });
|
||||||
return foundry.applications.handlebars.renderTemplate(template, chatData);
|
return foundry.applications.handlebars.renderTemplate(template, { ...chatData, metagamingSettings });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,8 @@ export default class DualityRoll extends D20Roll {
|
||||||
let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollString, evaluated: false });
|
let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollString, evaluated: false });
|
||||||
const term = parsedRoll.terms[target.dataset.dieIndex];
|
const term = parsedRoll.terms[target.dataset.dieIndex];
|
||||||
await term.reroll(`/r1=${term.total}`);
|
await term.reroll(`/r1=${term.total}`);
|
||||||
|
const result = await parsedRoll.evaluate();
|
||||||
|
|
||||||
if (game.modules.get('dice-so-nice')?.active) {
|
if (game.modules.get('dice-so-nice')?.active) {
|
||||||
const diceSoNiceRoll = {
|
const diceSoNiceRoll = {
|
||||||
_evaluated: true,
|
_evaluated: true,
|
||||||
|
|
@ -391,7 +393,7 @@ export default class DualityRoll extends D20Roll {
|
||||||
options: { appearance: {} }
|
options: { appearance: {} }
|
||||||
};
|
};
|
||||||
|
|
||||||
const diceSoNicePresets = await getDiceSoNicePresets(`d${term._faces}`, `d${term._faces}`);
|
const diceSoNicePresets = await getDiceSoNicePresets(result, `d${term._faces}`, `d${term._faces}`);
|
||||||
const type = target.dataset.type;
|
const type = target.dataset.type;
|
||||||
if (diceSoNicePresets[type]) {
|
if (diceSoNicePresets[type]) {
|
||||||
diceSoNiceRoll.dice[0].options = diceSoNicePresets[type];
|
diceSoNiceRoll.dice[0].options = diceSoNicePresets[type];
|
||||||
|
|
@ -400,8 +402,6 @@ export default class DualityRoll extends D20Roll {
|
||||||
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await parsedRoll.evaluate();
|
|
||||||
|
|
||||||
const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, {
|
const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, {
|
||||||
targets: message.system.targets,
|
targets: message.system.targets,
|
||||||
roll: {
|
roll: {
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,11 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
document = fromUuidSync(uuid);
|
document = fromUuidSync(uuid);
|
||||||
if (!document) return;
|
if (!document) return;
|
||||||
|
|
||||||
e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER'));
|
|
||||||
e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER'));
|
e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER'));
|
||||||
|
|
||||||
|
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming);
|
||||||
|
if (settings.hideObserverPermissionInChat)
|
||||||
|
e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER'));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.isContentVisible) {
|
if (this.isContentVisible) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { AdversaryBPPerEncounter, BaseBPPerEncounter } from '../config/encounter
|
||||||
export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager {
|
export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager {
|
||||||
#wide = false;
|
#wide = false;
|
||||||
#bordered = false;
|
#bordered = false;
|
||||||
|
#active = false;
|
||||||
|
|
||||||
async activate(element, options = {}) {
|
async activate(element, options = {}) {
|
||||||
const { TextEditor } = foundry.applications.ux;
|
const { TextEditor } = foundry.applications.ux;
|
||||||
|
|
@ -168,7 +169,100 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.activate(element, { ...options, html: html });
|
this.baseActivate(element, { ...options, html: html });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Need to pass more options to _setAnchor, so have to copy whole foundry method >_< */
|
||||||
|
async baseActivate(element, options) {
|
||||||
|
let { text, direction, cssClass, locked = false, html, content } = options;
|
||||||
|
if (content && !html) {
|
||||||
|
foundry.utils.logCompatibilityWarning(
|
||||||
|
'The content option has been deprecated in favor of the html option',
|
||||||
|
{ since: 13, until: 15, once: true }
|
||||||
|
);
|
||||||
|
html = content;
|
||||||
|
}
|
||||||
|
if (text && html) throw new Error('Cannot provide both text and html options to TooltipManager#activate.');
|
||||||
|
// Deactivate currently active element
|
||||||
|
this.deactivate();
|
||||||
|
// Check if the element still exists in the DOM.
|
||||||
|
if (!document.body.contains(element)) return;
|
||||||
|
// Mark the new element as active
|
||||||
|
this.#active = true;
|
||||||
|
this.element = element;
|
||||||
|
element.setAttribute('aria-describedby', 'tooltip');
|
||||||
|
html ||= element.dataset.tooltipHtml;
|
||||||
|
if (html) {
|
||||||
|
if (typeof html === 'string') this.tooltip.innerHTML = foundry.utils.cleanHTML(html);
|
||||||
|
else {
|
||||||
|
this.tooltip.innerHTML = ''; // Clear existing HTML
|
||||||
|
this.tooltip.appendChild(html);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text ||= element.dataset.tooltipText;
|
||||||
|
if (text) this.tooltip.textContent = text;
|
||||||
|
else {
|
||||||
|
text = element.dataset.tooltip;
|
||||||
|
// Localized message should be safe
|
||||||
|
if (game.i18n.has(text)) this.tooltip.innerHTML = game.i18n.localize(text);
|
||||||
|
else this.tooltip.innerHTML = foundry.utils.cleanHTML(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate display of the tooltip
|
||||||
|
this.tooltip.removeAttribute('class');
|
||||||
|
this.tooltip.classList.add('active', 'themed', 'theme-dark');
|
||||||
|
this.tooltip.showPopover();
|
||||||
|
cssClass ??= element.closest('[data-tooltip-class]')?.dataset.tooltipClass;
|
||||||
|
if (cssClass) this.tooltip.classList.add(...cssClass.split(' '));
|
||||||
|
|
||||||
|
// Set tooltip position
|
||||||
|
direction ??= element.closest('[data-tooltip-direction]')?.dataset.tooltipDirection;
|
||||||
|
if (!direction) direction = this._determineDirection();
|
||||||
|
this._setAnchor(direction, options);
|
||||||
|
|
||||||
|
if (locked || element.dataset.hasOwnProperty('locked')) this.lockTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
_setAnchor(direction, options) {
|
||||||
|
const directions = this.constructor.TOOLTIP_DIRECTIONS;
|
||||||
|
const pad = this.constructor.TOOLTIP_MARGIN_PX;
|
||||||
|
const pos = this.element.getBoundingClientRect();
|
||||||
|
|
||||||
|
const { innerHeight, innerWidth } = this.tooltip.ownerDocument.defaultView;
|
||||||
|
const tooltipPadding = 16;
|
||||||
|
const horizontalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetWidth / 2 - pos.width / 2;
|
||||||
|
const verticalOffset = options.noOffset ? tooltipPadding : this.tooltip.offsetHeight / 2 - pos.height / 2;
|
||||||
|
|
||||||
|
const style = {};
|
||||||
|
switch (direction) {
|
||||||
|
case directions.DOWN:
|
||||||
|
style.textAlign = 'center';
|
||||||
|
style.left = pos.left - horizontalOffset;
|
||||||
|
style.top = pos.bottom + pad;
|
||||||
|
break;
|
||||||
|
case directions.LEFT:
|
||||||
|
style.textAlign = 'left';
|
||||||
|
style.right = innerWidth - pos.left + pad;
|
||||||
|
style.top = pos.top - verticalOffset;
|
||||||
|
break;
|
||||||
|
case directions.RIGHT:
|
||||||
|
style.textAlign = 'right';
|
||||||
|
style.left = pos.right + pad;
|
||||||
|
style.top = pos.top - verticalOffset;
|
||||||
|
break;
|
||||||
|
case directions.UP:
|
||||||
|
style.textAlign = 'center';
|
||||||
|
style.left = pos.left - horizontalOffset;
|
||||||
|
style.bottom = innerHeight - pos.top + pad;
|
||||||
|
break;
|
||||||
|
case directions.CENTER:
|
||||||
|
style.textAlign = 'center';
|
||||||
|
style.left = pos.left - horizontalOffset;
|
||||||
|
style.top = pos.top - verticalOffset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this._setStyle(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
_determineItemTooltipDirection(element, prefered = this.constructor.TOOLTIP_DIRECTIONS.LEFT) {
|
_determineItemTooltipDirection(element, prefered = this.constructor.TOOLTIP_DIRECTIONS.LEFT) {
|
||||||
|
|
@ -270,6 +364,12 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**@inheritdoc */
|
||||||
|
dismissLockedTooltips() {
|
||||||
|
super.dismissLockedTooltips();
|
||||||
|
Hooks.callAll(CONFIG.DH.HOOKS.hooksConfig.lockedTooltipDismissed);
|
||||||
|
}
|
||||||
|
|
||||||
/** Get HTML for Battlepoints tooltip */
|
/** Get HTML for Battlepoints tooltip */
|
||||||
async getBattlepointHTML(combatId) {
|
async getBattlepointHTML(combatId) {
|
||||||
const combat = game.combats.get(combatId);
|
const combat = game.combats.get(combatId);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,13 @@ export const getCommandTarget = (options = {}) => {
|
||||||
|
|
||||||
export const setDiceSoNiceForDualityRoll = async (rollResult, advantageState, hopeFaces, fearFaces, advantageFaces) => {
|
export const setDiceSoNiceForDualityRoll = async (rollResult, advantageState, hopeFaces, fearFaces, advantageFaces) => {
|
||||||
if (!game.modules.get('dice-so-nice')?.active) return;
|
if (!game.modules.get('dice-so-nice')?.active) return;
|
||||||
const diceSoNicePresets = await getDiceSoNicePresets(hopeFaces, fearFaces, advantageFaces, advantageFaces);
|
const diceSoNicePresets = await getDiceSoNicePresets(
|
||||||
|
rollResult,
|
||||||
|
hopeFaces,
|
||||||
|
fearFaces,
|
||||||
|
advantageFaces,
|
||||||
|
advantageFaces
|
||||||
|
);
|
||||||
rollResult.dice[0].options = diceSoNicePresets.hope;
|
rollResult.dice[0].options = diceSoNicePresets.hope;
|
||||||
rollResult.dice[1].options = diceSoNicePresets.fear;
|
rollResult.dice[1].options = diceSoNicePresets.fear;
|
||||||
if (rollResult.dice[2] && advantageState) {
|
if (rollResult.dice[2] && advantageState) {
|
||||||
|
|
@ -378,17 +384,18 @@ export const arraysEqual = (a, b) =>
|
||||||
|
|
||||||
export const setsEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value));
|
export const setsEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value));
|
||||||
|
|
||||||
export function getScrollTextData(resources, resource, key) {
|
export function getScrollTextData(actor, resource, key) {
|
||||||
const { reversed, label } = CONFIG.DH.ACTOR.scrollingTextResource[key];
|
|
||||||
const { BOTTOM, TOP } = CONST.TEXT_ANCHOR_POINTS;
|
const { BOTTOM, TOP } = CONST.TEXT_ANCHOR_POINTS;
|
||||||
|
|
||||||
|
const resources = actor.system.resources;
|
||||||
const increased = resources[key].value < resource.value;
|
const increased = resources[key].value < resource.value;
|
||||||
const value = -1 * (resources[key].value - resource.value);
|
const value = -1 * (resources[key].value - resource.value);
|
||||||
|
const { label, isReversed } = resources[key];
|
||||||
|
|
||||||
const text = `${game.i18n.localize(label)} ${value.signedString()}`;
|
const text = `${game.i18n.localize(label)} ${value.signedString()}`;
|
||||||
|
const stroke = increased ? (isReversed ? 0xffffff : 0x000000) : isReversed ? 0x000000 : 0xffffff;
|
||||||
const stroke = increased ? (reversed ? 0xffffff : 0x000000) : reversed ? 0x000000 : 0xffffff;
|
const fill = increased ? (isReversed ? 0x0032b1 : 0xffe760) : isReversed ? 0xffe760 : 0x0032b1;
|
||||||
const fill = increased ? (reversed ? 0x0032b1 : 0xffe760) : reversed ? 0xffe760 : 0x0032b1;
|
const direction = increased ? (isReversed ? BOTTOM : TOP) : isReversed ? TOP : BOTTOM;
|
||||||
const direction = increased ? (reversed ? BOTTOM : TOP) : reversed ? TOP : BOTTOM;
|
|
||||||
|
|
||||||
return { text, stroke, fill, direction };
|
return { text, stroke, fill, direction };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'systems/daggerheart/templates/sheets/global/partials/resource-section/dice-value.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/resource-section/dice-value.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/resource-section/die.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/resource-section/die.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs',
|
'systems/daggerheart/templates/sheets/global/partials/resource-bar.hbs',
|
||||||
|
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
||||||
|
'systems/daggerheart/templates/sheets/global/partials/item-tags.hbs',
|
||||||
'systems/daggerheart/templates/components/card-preview.hbs',
|
'systems/daggerheart/templates/components/card-preview.hbs',
|
||||||
'systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs',
|
'systems/daggerheart/templates/levelup/parts/selectable-card-preview.hbs',
|
||||||
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',
|
|
||||||
'systems/daggerheart/templates/ui/combatTracker/combatTrackerSection.hbs',
|
'systems/daggerheart/templates/ui/combatTracker/combatTrackerSection.hbs',
|
||||||
'systems/daggerheart/templates/actionTypes/damage.hbs',
|
'systems/daggerheart/templates/actionTypes/damage.hbs',
|
||||||
'systems/daggerheart/templates/actionTypes/resource.hbs',
|
'systems/daggerheart/templates/actionTypes/resource.hbs',
|
||||||
|
|
@ -33,6 +34,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'systems/daggerheart/templates/actionTypes/beastform.hbs',
|
'systems/daggerheart/templates/actionTypes/beastform.hbs',
|
||||||
'systems/daggerheart/templates/actionTypes/countdown.hbs',
|
'systems/daggerheart/templates/actionTypes/countdown.hbs',
|
||||||
'systems/daggerheart/templates/actionTypes/summon.hbs',
|
'systems/daggerheart/templates/actionTypes/summon.hbs',
|
||||||
|
'systems/daggerheart/templates/actionTypes/transform.hbs',
|
||||||
'systems/daggerheart/templates/settings/components/settings-item-line.hbs',
|
'systems/daggerheart/templates/settings/components/settings-item-line.hbs',
|
||||||
'systems/daggerheart/templates/ui/tooltip/parts/tooltipChips.hbs',
|
'systems/daggerheart/templates/ui/tooltip/parts/tooltipChips.hbs',
|
||||||
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs',
|
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs',
|
||||||
|
|
@ -44,6 +46,7 @@ export const preloadHandlebarsTemplates = async function () {
|
||||||
'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',
|
||||||
'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
|
'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
|
||||||
'systems/daggerheart/templates/scene/dh-config.hbs'
|
'systems/daggerheart/templates/scene/dh-config.hbs',
|
||||||
|
'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs'
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
|
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
|
||||||
import DhCountdowns from '../data/countdowns.mjs';
|
import DhCountdowns from '../data/countdowns.mjs';
|
||||||
import { DhAppearance, DhAutomation, DhHomebrew, DhVariantRules } from '../data/settings/_module.mjs';
|
import {
|
||||||
|
DhAppearance,
|
||||||
|
DhAutomation,
|
||||||
|
DhGlobalOverrides,
|
||||||
|
DhHomebrew,
|
||||||
|
DhMetagaming,
|
||||||
|
DhVariantRules
|
||||||
|
} from '../data/settings/_module.mjs';
|
||||||
import {
|
import {
|
||||||
DhAppearanceSettings,
|
DhAppearanceSettings,
|
||||||
DhAutomationSettings,
|
DhAutomationSettings,
|
||||||
DhHomebrewSettings,
|
DhHomebrewSettings,
|
||||||
|
DhMetagamingSettings,
|
||||||
DhVariantRuleSettings
|
DhVariantRuleSettings
|
||||||
} from '../applications/settings/_module.mjs';
|
} from '../applications/settings/_module.mjs';
|
||||||
import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs';
|
import { CompendiumBrowserSettings, DhTagTeamRoll } from '../data/_module.mjs';
|
||||||
|
|
@ -38,18 +46,25 @@ const registerMenuSettings = () => {
|
||||||
type: DhAutomation
|
type: DhAutomation
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming, {
|
||||||
|
scope: 'world',
|
||||||
|
config: false,
|
||||||
|
type: DhMetagaming
|
||||||
|
});
|
||||||
|
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, {
|
||||||
scope: 'world',
|
scope: 'world',
|
||||||
config: false,
|
config: false,
|
||||||
type: DhHomebrew,
|
type: DhHomebrew,
|
||||||
onChange: value => {
|
onChange: value => {
|
||||||
if (value.maxFear) {
|
value.handleChange();
|
||||||
if (ui.resources) ui.resources.render({ force: true });
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Some homebrew settings may change sheets in various ways, so trigger a re-render
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, {
|
||||||
resetActors();
|
scope: 'world',
|
||||||
}
|
config: false,
|
||||||
|
type: DhGlobalOverrides
|
||||||
});
|
});
|
||||||
|
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, {
|
||||||
|
|
@ -57,12 +72,7 @@ const registerMenuSettings = () => {
|
||||||
config: false,
|
config: false,
|
||||||
type: DhAppearance,
|
type: DhAppearance,
|
||||||
onChange: value => {
|
onChange: value => {
|
||||||
if (value.displayFear) {
|
value.handleChange();
|
||||||
if (ui.resources) {
|
|
||||||
if (value.displayFear === 'hide') ui.resources.close({ allowed: true });
|
|
||||||
else ui.resources.render({ force: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
@ -76,6 +86,16 @@ const registerMenus = () => {
|
||||||
type: DhAutomationSettings,
|
type: DhAutomationSettings,
|
||||||
restricted: true
|
restricted: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.registerMenu(CONFIG.DH.id, CONFIG.DH.SETTINGS.menu.Metagaming.Name, {
|
||||||
|
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.metagaming.name'),
|
||||||
|
label: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.metagaming.label'),
|
||||||
|
hint: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.metagaming.hint'),
|
||||||
|
icon: CONFIG.DH.SETTINGS.menu.Metagaming.Icon,
|
||||||
|
type: DhMetagamingSettings,
|
||||||
|
restricted: true
|
||||||
|
});
|
||||||
|
|
||||||
game.settings.registerMenu(CONFIG.DH.id, CONFIG.DH.SETTINGS.menu.Homebrew.Name, {
|
game.settings.registerMenu(CONFIG.DH.id, CONFIG.DH.SETTINGS.menu.Homebrew.Name, {
|
||||||
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.homebrew.name'),
|
name: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.homebrew.name'),
|
||||||
label: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.homebrew.label'),
|
label: game.i18n.localize('DAGGERHEART.SETTINGS.Menu.homebrew.label'),
|
||||||
|
|
@ -144,30 +164,8 @@ const registerNonConfigSettings = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.CompendiumBrowserSettings, {
|
||||||
scope: 'client',
|
scope: 'world',
|
||||||
config: false,
|
config: false,
|
||||||
type: CompendiumBrowserSettings
|
type: CompendiumBrowserSettings
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers a reset and non-forced re-render on all given actors (if given)
|
|
||||||
* or all world actors and actors in all scenes to show immediate results for a changed setting.
|
|
||||||
*/
|
|
||||||
function resetActors(actors) {
|
|
||||||
actors ??= [
|
|
||||||
game.actors.contents,
|
|
||||||
game.scenes.contents.flatMap(s => s.tokens.contents).flatMap(t => t.actor ?? [])
|
|
||||||
].flat();
|
|
||||||
actors = new Set(actors);
|
|
||||||
for (const actor of actors) {
|
|
||||||
for (const app of Object.values(actor.apps)) {
|
|
||||||
for (const element of app.element?.querySelectorAll('prose-mirror.active')) {
|
|
||||||
element.open = false; // This triggers a save
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
actor.reset();
|
|
||||||
actor.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -717,7 +717,35 @@
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.RXkZTwBRi4dJ3JE5]{Fallen Warlord: Undefeated Champion} and immediately spotlight them.</p>",
|
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.RXkZTwBRi4dJ3JE5]{Fallen Warlord: Undefeated Champion} and immediately spotlight them.</p>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {},
|
"actions": {
|
||||||
|
"gP426WmWbtrZEWCD": {
|
||||||
|
"type": "transform",
|
||||||
|
"_id": "gP426WmWbtrZEWCD",
|
||||||
|
"systemPath": "actions",
|
||||||
|
"baseAction": false,
|
||||||
|
"description": "",
|
||||||
|
"chatDisplay": true,
|
||||||
|
"originItem": {
|
||||||
|
"type": "itemCollection"
|
||||||
|
},
|
||||||
|
"actionType": "action",
|
||||||
|
"triggers": [],
|
||||||
|
"cost": [],
|
||||||
|
"uses": {
|
||||||
|
"value": null,
|
||||||
|
"max": null,
|
||||||
|
"recovery": null,
|
||||||
|
"consumeOnSuccess": false
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.RXkZTwBRi4dJ3JE5",
|
||||||
|
"resourceRefresh": {
|
||||||
|
"hitPoints": true,
|
||||||
|
"stress": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"originItemType": null,
|
"originItemType": null,
|
||||||
"originId": null,
|
"originId": null,
|
||||||
"featureForm": "reaction"
|
"featureForm": "reaction"
|
||||||
|
|
|
||||||
|
|
@ -857,7 +857,37 @@
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.pMuXGCSOQaxpi5tb]{Ashen Tyrant} and immediately spotlight them.</p>",
|
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.pMuXGCSOQaxpi5tb]{Ashen Tyrant} and immediately spotlight them.</p>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {},
|
"actions": {
|
||||||
|
"cFqFjemAfAjB0OB0": {
|
||||||
|
"type": "transform",
|
||||||
|
"_id": "cFqFjemAfAjB0OB0",
|
||||||
|
"systemPath": "actions",
|
||||||
|
"baseAction": false,
|
||||||
|
"description": "",
|
||||||
|
"chatDisplay": true,
|
||||||
|
"originItem": {
|
||||||
|
"type": "itemCollection"
|
||||||
|
},
|
||||||
|
"actionType": "action",
|
||||||
|
"triggers": [],
|
||||||
|
"cost": [],
|
||||||
|
"uses": {
|
||||||
|
"value": null,
|
||||||
|
"max": "",
|
||||||
|
"recovery": null,
|
||||||
|
"consumeOnSuccess": false
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.pMuXGCSOQaxpi5tb",
|
||||||
|
"resourceRefresh": {
|
||||||
|
"hitPoints": true,
|
||||||
|
"stress": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Transform",
|
||||||
|
"range": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"originItemType": null,
|
"originItemType": null,
|
||||||
"originId": null,
|
"originId": null,
|
||||||
"featureForm": "reaction"
|
"featureForm": "reaction"
|
||||||
|
|
|
||||||
|
|
@ -742,7 +742,37 @@
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.eArAPuB38CNR0ZIM]{Molten Scourge} and immediately spotlight them.</p>",
|
"description": "<p>When the @Lookup[@name] marks their last HP, replace them with the @UUID[Compendium.daggerheart.adversaries.Actor.eArAPuB38CNR0ZIM]{Molten Scourge} and immediately spotlight them.</p>",
|
||||||
"resource": null,
|
"resource": null,
|
||||||
"actions": {},
|
"actions": {
|
||||||
|
"OxGkCGgIl4vGFufD": {
|
||||||
|
"type": "transform",
|
||||||
|
"_id": "OxGkCGgIl4vGFufD",
|
||||||
|
"systemPath": "actions",
|
||||||
|
"baseAction": false,
|
||||||
|
"description": "",
|
||||||
|
"chatDisplay": true,
|
||||||
|
"originItem": {
|
||||||
|
"type": "itemCollection"
|
||||||
|
},
|
||||||
|
"actionType": "action",
|
||||||
|
"triggers": [],
|
||||||
|
"cost": [],
|
||||||
|
"uses": {
|
||||||
|
"value": null,
|
||||||
|
"max": "",
|
||||||
|
"recovery": null,
|
||||||
|
"consumeOnSuccess": false
|
||||||
|
},
|
||||||
|
"transform": {
|
||||||
|
"actorUUID": "Compendium.daggerheart.adversaries.Actor.eArAPuB38CNR0ZIM",
|
||||||
|
"resourceRefresh": {
|
||||||
|
"hitPoints": true,
|
||||||
|
"stress": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Transform",
|
||||||
|
"range": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"originItemType": null,
|
"originItemType": null,
|
||||||
"originId": null,
|
"originId": null,
|
||||||
"featureForm": "reaction"
|
"featureForm": "reaction"
|
||||||
|
|
|
||||||
|
|
@ -153,9 +153,9 @@
|
||||||
},
|
},
|
||||||
"effects": [],
|
"effects": [],
|
||||||
"roll": {
|
"roll": {
|
||||||
"type": null,
|
"type": "spellcast",
|
||||||
"trait": null,
|
"trait": null,
|
||||||
"difficulty": null,
|
"difficulty": 13,
|
||||||
"bonus": null,
|
"bonus": null,
|
||||||
"advState": "neutral",
|
"advState": "neutral",
|
||||||
"diceRolling": {
|
"diceRolling": {
|
||||||
|
|
|
||||||
|
|
@ -574,61 +574,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.application.setting.dh-style {
|
.application.setting.dh-style {
|
||||||
fieldset {
|
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
h4 {
|
h4 {
|
||||||
margin: 8px 0 4px;
|
margin: 8px 0 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.title-hint {
|
|
||||||
font-size: var(--font-size-12);
|
|
||||||
font-variant: small-caps;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.split-section {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.label-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
&.full-width {
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
|
|
||||||
select {
|
|
||||||
grid-column: span 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
align-self: center;
|
|
||||||
text-align: center;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
gap: 10px;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,24 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
align-items: center;
|
||||||
|
background: light-dark(@dark-15, @beige-15);
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid light-dark(@dark, @beige);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
justify-content: start;
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Remove me when this issue is resolved https://github.com/foundryvtt/foundryvtt/issues/13734 */
|
/* TODO: Remove me when this issue is resolved https://github.com/foundryvtt/foundryvtt/issues/13734 */
|
||||||
|
|
|
||||||
|
|
@ -138,24 +138,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-tags {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.tag {
|
|
||||||
align-items: center;
|
|
||||||
background: light-dark(@dark-15, @beige-15);
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid light-dark(@dark, @beige);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
font-size: var(--font-size-12);
|
|
||||||
justify-content: start;
|
|
||||||
padding: 3px 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-resource {
|
.item-resource {
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,37 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.actor-summon-line {
|
.transform-container {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.transform-resources {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.transform-resource {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
|
||||||
|
.resource-title {
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-drop-line {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
|
||||||
.actor-summon-name {
|
.actor-drop-name {
|
||||||
flex: 2;
|
flex: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -22,20 +45,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.actor-summon-controls {
|
.actor-drop-controls {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|
||||||
|
&.transform {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.actor-drop-hint {
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.summon-dragger {
|
.drop-dragger {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -46,7 +77,6 @@
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: light-dark(@dark-blue-50, @beige-50);
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-data {
|
.trigger-data {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
||||||
|
|
@ -133,8 +133,19 @@
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
.hope-section {
|
.resource-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
|
||||||
|
.resource-manager {
|
||||||
|
transition: all 0.1s ease;
|
||||||
|
|
||||||
|
&.inverted {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.downtime-section {
|
.downtime-section {
|
||||||
|
|
|
||||||
|
|
@ -450,6 +450,10 @@
|
||||||
|
|
||||||
.target-data {
|
.target-data {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
.target-name {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.target-save {
|
.target-save {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@
|
||||||
@import './settings/settings.less';
|
@import './settings/settings.less';
|
||||||
@import './settings/homebrew-settings/domains.less';
|
@import './settings/homebrew-settings/domains.less';
|
||||||
@import './settings/homebrew-settings/types.less';
|
@import './settings/homebrew-settings/types.less';
|
||||||
|
@import './settings/homebrew-settings/resources.less';
|
||||||
|
@import './settings/appearance-settings/diceSoNice.less';
|
||||||
|
|
||||||
@import './sidebar/tabs.less';
|
@import './sidebar/tabs.less';
|
||||||
@import './sidebar/daggerheartMenu.less';
|
@import './sidebar/daggerheartMenu.less';
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,15 @@
|
||||||
padding: 0 0 0 50px;
|
padding: 0 0 0 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
|
||||||
|
.item-description-outer-container:has(div, p) {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some items don't include an outer container, so we attempt a catch-all */
|
||||||
|
> *:last-child {
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: var(--font-size-32);
|
font-size: var(--font-size-32);
|
||||||
|
|
@ -350,6 +358,7 @@
|
||||||
.filter-content,
|
.filter-content,
|
||||||
.item-desc {
|
.item-desc {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
opacity: 0;
|
||||||
grid-template-rows: 0fr;
|
grid-template-rows: 0fr;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -378,8 +387,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.expanded + .extensible {
|
.expanded + .extensible {
|
||||||
|
opacity: 1;
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
padding-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.welcome-message {
|
.welcome-message {
|
||||||
|
|
|
||||||
72
styles/less/ui/settings/appearance-settings/diceSoNice.less
Normal file
72
styles/less/ui/settings/appearance-settings/diceSoNice.less
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
.daggerheart.dh-style.setting.appearance-settings {
|
||||||
|
.tab.active[data-tab='diceSoNice'] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diceSoNice-footer {
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-hint {
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
font-variant: small-caps;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.split-section {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
grid-column: span 2;
|
||||||
|
text-align: center;
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
&.full-width {
|
||||||
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
|
|
||||||
|
select {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
align-self: center;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
87
styles/less/ui/settings/homebrew-settings/resources.less
Normal file
87
styles/less/ui/settings/homebrew-settings/resources.less
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
.daggerheart.dh-style.setting.homebrew-settings .resources.tab {
|
||||||
|
.resource-types-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
overflow: auto;
|
||||||
|
max-height: 570px;
|
||||||
|
|
||||||
|
fieldset legend {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-type-container {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.resources-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.resource-container {
|
||||||
|
.resource-icons-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.resource-icon-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.resource-icon-title-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
color: @dark-blue;
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, @golden 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background: linear-gradient(90deg, @golden 0%, rgba(0, 0, 0, 0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-icon-title {
|
||||||
|
font-size: var(--font-size-16);
|
||||||
|
white-space: nowrap;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.two-columns {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group.vertical {
|
||||||
|
> * {
|
||||||
|
flex: 0 0 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,3 +4,5 @@
|
||||||
@import './tooltip/domain-cards.less';
|
@import './tooltip/domain-cards.less';
|
||||||
|
|
||||||
@import './autocomplete/autocomplete.less';
|
@import './autocomplete/autocomplete.less';
|
||||||
|
|
||||||
|
@import './tooltip/resource-management.less';
|
||||||
|
|
|
||||||
56
styles/less/ux/tooltip/resource-management.less
Normal file
56
styles/less/ux/tooltip/resource-management.less
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
.bordered-tooltip.locked-tooltip .daggerheart.resource-management-container,
|
||||||
|
#tooltip .daggerheart.resource-management-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.resource-section {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
background-color: light-dark(transparent, @dark-blue);
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid light-dark(@dark-blue, @golden);
|
||||||
|
border-radius: 6px;
|
||||||
|
align-items: center;
|
||||||
|
width: fit-content;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-family: var(--dh-font-body, 'Montserrat'), sans-serif;
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
font-weight: bold;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resource-value {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
|
||||||
|
&.empty {
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.filter {
|
||||||
|
filter: @golden-filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.non-transparent {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid @golden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<fieldset class="one-column" id="summon-drop-zone" data-key="summon">
|
<fieldset class="one-column" id="summon-drop-zone" data-is-drop-zone="true" data-key="summon">
|
||||||
<legend>
|
<legend>
|
||||||
{{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
|
{{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
<ul class="actor-summon-items">
|
<ul class="actor-summon-items">
|
||||||
{{#each @root.summons as |summon index|}}
|
{{#each @root.summons as |summon index|}}
|
||||||
<li class="actor-summon-line">
|
<li class="actor-drop-line">
|
||||||
<div class="actor-summon-name">
|
<div class="actor-drop-name">
|
||||||
<img class="image" src="{{summon.actor.img}}" />
|
<img class="image" src="{{summon.actor.img}}" />
|
||||||
<h4 class="h4">
|
<h4 class="h4">
|
||||||
{{summon.actor.name}}
|
{{summon.actor.name}}
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actor-summon-controls">
|
<div class="actor-drop-controls">
|
||||||
<div class="form-group summon-count-wrapper" data-index="{{index}}">
|
<div class="form-group summon-count-wrapper" data-index="{{index}}">
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
<input type="text" value="{{summon.count}}" />
|
<input type="text" value="{{summon.count}}" />
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<div class="summon-dragger">
|
<div class="drop-dragger">
|
||||||
<span>{{localize "DAGGERHEART.ACTIONS.Settings.summon.dropSummonsHere"}}</span>
|
<span>{{localize "DAGGERHEART.ACTIONS.Settings.summon.dropSummonsHere"}}</span>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
62
templates/actionTypes/transform.hbs
Normal file
62
templates/actionTypes/transform.hbs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<fieldset class="one-column" id="transform-drop-zone" data-is-drop-zone="true" data-key="transform">
|
||||||
|
<legend>
|
||||||
|
{{localize "DAGGERHEART.ACTIONS.TYPES.transform.name"}}
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<div class="transform-container">
|
||||||
|
{{#if transform.actor}}
|
||||||
|
<div class="actor-drop-line">
|
||||||
|
{{#if transform.actor.error}}
|
||||||
|
<div class="hint actor-drop-hint">{{transform.actor.error}}</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="actor-drop-name">
|
||||||
|
<img class="image" src="{{transform.actor.img}}" />
|
||||||
|
<h4 class="h4">
|
||||||
|
{{transform.actor.name}}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="actor-drop-controls transform">
|
||||||
|
<div class="controls">
|
||||||
|
{{#unless transform.actor.error}}
|
||||||
|
<a
|
||||||
|
class='effect-control'
|
||||||
|
data-action='editDoc'
|
||||||
|
data-item-uuid="{{transform.actor.uuid}}"
|
||||||
|
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
</a>
|
||||||
|
{{/unless}}
|
||||||
|
<a
|
||||||
|
class='effect-control'
|
||||||
|
data-action='removeTransformActor'
|
||||||
|
data-tooltip='{{localize "CONTROLS.CommonDelete"}}'
|
||||||
|
>
|
||||||
|
<i class='fas fa-trash'></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<line-div></line-div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#unless transform.actor}}
|
||||||
|
<div class="drop-dragger">
|
||||||
|
<span>{{localize "DAGGERHEART.ACTIONS.Settings.transform.dropTransformHere"}}</span>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
|
<div class="transform-resources">
|
||||||
|
<div class="transform-resource">
|
||||||
|
<input type="checkbox" data-resource="hitPoints" {{checked transform.resourceRefresh.hitPoints}}/>
|
||||||
|
<span class="resource-title">{{localize "DAGGERHEART.ACTIONS.Settings.transform.clearHitPoints"}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="transform-resource">
|
||||||
|
<input type="checkbox" data-resource="stress" {{checked transform.resourceRefresh.stress}}/>
|
||||||
|
<span class="resource-title">{{localize "DAGGERHEART.ACTIONS.Settings.transform.clearStress"}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
@ -1,7 +1,19 @@
|
||||||
<section class="tab {{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
<section class="tab {{#if tab.active}} active{{/if}}" data-group="{{tab.group}}" data-tab="{{tab.id}}">
|
||||||
<fieldset>
|
|
||||||
<div class="title-hint">{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.hint"}}</div>
|
<div class="title-hint">{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.hint"}}</div>
|
||||||
|
<div class="field-section form-fields">
|
||||||
|
{{#if isGM}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="dsn-overrideEnabled">{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.defaultAnimations"}}</label>
|
||||||
|
<input id="dsn-overrideEnabled" type="checkbox" class="default-animations-input" {{checked globalOverrides.diceSoNice.sfx.overrideEnabled}} />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.critical"}}</label>
|
||||||
|
<div class="form-fields">
|
||||||
|
{{formInput fields.diceSoNice.fields.sfx.fields.critical.fields.class value=setting.diceSoNice.sfx.critical.class blank="" localize=true}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<section class='tab-navigation'>
|
<section class='tab-navigation'>
|
||||||
<div class='navigation-container'>
|
<div class='navigation-container'>
|
||||||
<div class="navigation-inner-container">
|
<div class="navigation-inner-container">
|
||||||
|
|
@ -19,53 +31,7 @@
|
||||||
</section>
|
</section>
|
||||||
{{#each dsnTabs as |dsnTab|}}
|
{{#each dsnTabs as |dsnTab|}}
|
||||||
<section class="tab {{#if dsnTab.active}} active{{/if}}" data-group="{{dsnTab.group}}" data-tab="{{dsnTab.id}}">
|
<section class="tab {{#if dsnTab.active}} active{{/if}}" data-group="{{dsnTab.group}}" data-tab="{{dsnTab.id}}">
|
||||||
<div class="field-section">
|
{{> "systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs" dsnTab }}
|
||||||
<div class="label-container full-width">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.system"}}</label>
|
|
||||||
{{formInput fields.system value=values.system localize=true choices=@root.diceSoNiceSystems}}
|
|
||||||
</div>
|
|
||||||
<div class="split-section">
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.foreground"}}</label>
|
|
||||||
{{formInput fields.foreground value=values.foreground localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.background"}}</label>
|
|
||||||
{{formInput fields.background value=values.background localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.outline"}}</label>
|
|
||||||
{{formInput fields.outline value=values.outline localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.edge"}}</label>
|
|
||||||
{{formInput fields.edge value=values.edge localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.colorset"}}</label>
|
|
||||||
{{formInput fields.colorset value=values.colorset choices=@root.diceSoNiceColorsets localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.texture"}}</label>
|
|
||||||
{{formInput fields.texture value=values.texture choices=@root.diceSoNiceTextures localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.material"}}</label>
|
|
||||||
{{formInput fields.material value=values.material choices=@root.diceSoNiceMaterials localize=true}}
|
|
||||||
</div>
|
|
||||||
<div class="label-container">
|
|
||||||
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.font"}}</label>
|
|
||||||
{{formInput fields.font value=values.font choices=@root.diceSoNiceFonts localize=true}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="button-container">
|
|
||||||
<button type="button" data-action="preview" data-key="{{dsnTab.id}}">
|
|
||||||
<i class="fa-solid fa-dice"></i>
|
|
||||||
<span>{{localize "Preview"}}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</fieldset>
|
|
||||||
</section>
|
</section>
|
||||||
62
templates/settings/appearance-settings/diceSoNiceTab.hbs
Normal file
62
templates/settings/appearance-settings/diceSoNiceTab.hbs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
<div class="field-section">
|
||||||
|
<h3>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.diceAppearance"}}</h3>
|
||||||
|
|
||||||
|
<div class="label-container full-width">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.system"}}</label>
|
||||||
|
{{formInput fields.system value=values.system localize=true choices=@root.diceSoNiceSystems}}
|
||||||
|
</div>
|
||||||
|
<div class="split-section">
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.foreground"}}</label>
|
||||||
|
{{formInput fields.foreground value=values.foreground localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.background"}}</label>
|
||||||
|
{{formInput fields.background value=values.background localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.outline"}}</label>
|
||||||
|
{{formInput fields.outline value=values.outline localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.edge"}}</label>
|
||||||
|
{{formInput fields.edge value=values.edge localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.colorset"}}</label>
|
||||||
|
{{formInput fields.colorset value=values.colorset choices=@root.diceSoNiceColorsets localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.texture"}}</label>
|
||||||
|
{{formInput fields.texture value=values.texture choices=@root.diceSoNiceTextures localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.material"}}</label>
|
||||||
|
{{formInput fields.material value=values.material choices=@root.diceSoNiceMaterials localize=true}}
|
||||||
|
</div>
|
||||||
|
<div class="label-container">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.font"}}</label>
|
||||||
|
{{formInput fields.font value=values.font choices=@root.diceSoNiceFonts localize=true}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if animations}}
|
||||||
|
<h3>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.animations"}}</h3>
|
||||||
|
<div class="label-container full-width">
|
||||||
|
<label>{{localize "DAGGERHEART.CONFIG.DaggerheartDiceAnimationEvents.higher.name"}}</label>
|
||||||
|
{{formInput fields.sfx.fields.higher.fields.class value=values.sfx.higher.class blank="" localize=true}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="diceSoNice-footer">
|
||||||
|
<label>{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.previewAnimation"}}</label>
|
||||||
|
<select name="{{concat id "PreviewAnimation"}}">
|
||||||
|
{{selectOptions @root.animationEvents selected=@root.previewAnimation blank="" localize=true }}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="button" data-action="preview" data-key="{{id}}">
|
||||||
|
<i class="fa-solid fa-dice"></i>
|
||||||
|
<span>{{localize "DAGGERHEART.GENERAL.preview"}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
78
templates/settings/homebrew-settings/resources.hbs
Normal file
78
templates/settings/homebrew-settings/resources.hbs
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
<section
|
||||||
|
class="tab {{tabs.resources.cssClass}} {{tabs.resources.id}} scrollable"
|
||||||
|
data-tab="{{tabs.resources.id}}"
|
||||||
|
data-group="{{tabs.resources.group}}"
|
||||||
|
>
|
||||||
|
<div class="resource-types-container">
|
||||||
|
{{#each settingFields.resources as |type key|}}
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
{{localize "DAGGERHEART.SETTINGS.Homebrew.resources.typeTitle" type=(localize (concat "TYPES.Actor." key))}}
|
||||||
|
<a data-action="addResource" data-actor-type="{{key}}"><i class="fa-solid fa-plus"></i></a>
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<div class="resource-type-container">
|
||||||
|
<div class="resources-container">
|
||||||
|
{{#each type.resources as |resource key|}}
|
||||||
|
<fieldset class="resource-container">
|
||||||
|
<legend>{{resource.label}}<a data-action="removeResource" data-actor-type="{{@../key}}" data-resource-key="{{key}}"><i class="fa-solid fa-trash"></i></a></legend>
|
||||||
|
|
||||||
|
{{formField @root.schemaFields.resources.element.fields.resources.element.fields.label value=resource.label name=(concat "resources." @../key ".resources." key ".label") classes="vertical" localize=true }}
|
||||||
|
|
||||||
|
<div class="two-columns even">
|
||||||
|
{{formField @root.schemaFields.resources.element.fields.resources.element.fields.initial value=resource.initial name=(concat "resources." @../key ".resources." key ".initial") classes="vertical" localize=true }}
|
||||||
|
{{formField @root.schemaFields.resources.element.fields.resources.element.fields.max value=resource.max name=(concat "resources." @../key ".resources." key ".max") classes="vertical" localize=true }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="resource-icons-container">
|
||||||
|
<div class="resource-icon-container" data-actor-type="{{@../key}}" data-resource-key="{{key}}" data-image-key="full">
|
||||||
|
{{#with @root.schemaFields.resources.element.fields.resources.element.fields.images.fields.full.fields}}
|
||||||
|
<div class="resource-icon-title-container">
|
||||||
|
<div class="resource-icon-title">
|
||||||
|
<span>{{localize "DAGGERHEART.SETTINGS.Homebrew.resources.filledIcon"}}</span>
|
||||||
|
<a data-action="resetResourceImage"><i class="fa-solid fa-arrow-rotate-left"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="resource-icon-content">
|
||||||
|
{{#if ../images.full.isIcon}}
|
||||||
|
{{formGroup this.value value=../images.full.value name=(concat "resources." @../key ".resources." key ".images.full.value") localize=true }}
|
||||||
|
{{else}}
|
||||||
|
<div class="form-fields">
|
||||||
|
<file-picker name="{{concat "resources." @../key ".resources." key ".images.full.value"}}" value="{{../images.full.value}}" type="image"></file-picker>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{formGroup this.isIcon value=../images.full.isIcon name="" classes="path-field" localize=true }}
|
||||||
|
{{formGroup this.noColorFilter value=../images.full.noColorFilter name=(concat "resources." @../key ".resources." key ".images.full.noColorFilter") localize=true }}
|
||||||
|
</div>
|
||||||
|
{{/with}}
|
||||||
|
</div>
|
||||||
|
<div class="resource-icon-container" data-actor-type="{{@../key}}" data-resource-key="{{key}}" data-image-key="empty">
|
||||||
|
{{#with @root.schemaFields.resources.element.fields.resources.element.fields.images.fields.empty.fields}}
|
||||||
|
<div class="resource-icon-title-container">
|
||||||
|
<div class="resource-icon-title">
|
||||||
|
<span>{{localize "DAGGERHEART.SETTINGS.Homebrew.resources.emptyIcon"}}</span>
|
||||||
|
<a data-action="resetResourceImage"><i class="fa-solid fa-arrow-rotate-left"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="resource-icon-content">
|
||||||
|
{{#if ../images.empty.isIcon}}
|
||||||
|
{{formGroup this.value value=../images.empty.value name=(concat "resources." @../key ".resources." key ".images.empty.value") localize=true }}
|
||||||
|
{{else}}
|
||||||
|
<div class="form-fields">
|
||||||
|
<file-picker name="{{concat "resources." @../key ".resources." key ".images.empty.value"}}" value="{{../images.empty.value}}" type="image"></file-picker>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{formGroup this.isIcon value=resource.images.empty.isIcon name="" classes="path-field" localize=true }}
|
||||||
|
{{formGroup this.noColorFilter value=resource.images.empty.noColorFilter name=(concat "resources." @../key ".resources." key ".images.empty.noColorFilter") localize=true }}
|
||||||
|
</div>
|
||||||
|
{{/with}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
10
templates/settings/metagaming-settings/footer.hbs
Normal file
10
templates/settings/metagaming-settings/footer.hbs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<footer class="form-footer">
|
||||||
|
<button data-action="reset">
|
||||||
|
<i class="fa-solid fa-arrow-rotate-left"></i>
|
||||||
|
<span>{{localize "Reset"}}</span>
|
||||||
|
</button>
|
||||||
|
<button data-action="save" >
|
||||||
|
<i class="fa-solid fa-floppy-disk"></i>
|
||||||
|
<span>{{localize "Save Changes"}}</span>
|
||||||
|
</button>
|
||||||
|
</footer>
|
||||||
3
templates/settings/metagaming-settings/general.hbs
Normal file
3
templates/settings/metagaming-settings/general.hbs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<div>
|
||||||
|
{{formGroup settingFields.schema.fields.hideObserverPermissionInChat value=settingFields._source.hideObserverPermissionInChat localize=true}}
|
||||||
|
</div>
|
||||||
3
templates/settings/metagaming-settings/header.hbs
Normal file
3
templates/settings/metagaming-settings/header.hbs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<header class="dialog-header">
|
||||||
|
<h1>{{localize 'DAGGERHEART.SETTINGS.Menu.metagaming.name'}}</h1>
|
||||||
|
</header>
|
||||||
|
|
@ -11,4 +11,5 @@
|
||||||
{{#if fields.beastform}}{{> 'systems/daggerheart/templates/actionTypes/beastform.hbs' fields=fields.beastform.fields source=source.beastform}}{{/if}}
|
{{#if fields.beastform}}{{> 'systems/daggerheart/templates/actionTypes/beastform.hbs' fields=fields.beastform.fields source=source.beastform}}{{/if}}
|
||||||
{{#if fields.summon}}{{> 'systems/daggerheart/templates/actionTypes/summon.hbs' fields=fields.summon.element.fields source=source.summon}}{{/if}}
|
{{#if fields.summon}}{{> 'systems/daggerheart/templates/actionTypes/summon.hbs' fields=fields.summon.element.fields source=source.summon}}{{/if}}
|
||||||
{{#if fields.countdown}}{{> 'systems/daggerheart/templates/actionTypes/countdown.hbs' fields=fields.countdown.element.fields source=source.countdown}}{{/if}}
|
{{#if fields.countdown}}{{> 'systems/daggerheart/templates/actionTypes/countdown.hbs' fields=fields.countdown.element.fields source=source.countdown}}{{/if}}
|
||||||
|
{{#if fields.transform}}{{> 'systems/daggerheart/templates/actionTypes/transform.hbs' fields=fields.transform.fields source=source.transform}}{{/if}}
|
||||||
</section>
|
</section>
|
||||||
|
|
@ -20,14 +20,10 @@
|
||||||
|
|
||||||
<div class="fieldsets-section">
|
<div class="fieldsets-section">
|
||||||
<fieldset class="flex">
|
<fieldset class="flex">
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.HitPoints.plural"}}</legend>
|
<legend>{{localize "DAGGERHEART.GENERAL.Resource.plural"}}</legend>
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.value.label")}}
|
{{#each resources as |resource|}}
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.hitPoints.max.label")}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
</fieldset>
|
{{/each}}
|
||||||
<fieldset class="flex">
|
|
||||||
<legend>{{localize "DAGGERHEART.GENERAL.stress"}}</legend>
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.value.label")}}
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max label=(localize "DAGGERHEART.ACTORS.Adversary.FIELDS.resources.stress.max.label")}}
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,12 @@
|
||||||
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
||||||
|
|
||||||
<div class="two-columns even">
|
<div class="two-columns even">
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value localize=true}}
|
{{#each resources as |resource|}}
|
||||||
<span data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.maxHPClassBound"}}">
|
<span {{#if resource.tooltip}}data-tooltip-text="{{resource.tooltip}}"{{/if}}>
|
||||||
{{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max localize=true}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
</span>
|
</span>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value localize=true}}
|
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max localize=true}}
|
|
||||||
|
|
||||||
{{formGroup systemFields.resources.fields.hope.fields.value value=document._source.system.resources.hope.value localize=true}}
|
|
||||||
{{formGroup systemFields.scars value=document._source.system.scars localize=true}}
|
{{formGroup systemFields.scars value=document._source.system.scars localize=true}}
|
||||||
|
|
||||||
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
|
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@
|
||||||
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
|
||||||
<div class="nest-inputs">
|
<div class="nest-inputs">
|
||||||
{{formGroup systemFields.evasion value=document._source.system.evasion localize=true}}
|
{{formGroup systemFields.evasion value=document._source.system.evasion localize=true}}
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.currentStress.label' localize=true}}
|
{{#each resources as |resource|}}
|
||||||
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max label='DAGGERHEART.ACTORS.Companion.FIELDS.resources.stress.maxStress.label' localize=true}}
|
{{formGroup resource.field value=resource.value name=resource.name}}
|
||||||
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-fields">
|
<div class="form-fields">
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
{{> 'daggerheart.inventory-items'
|
{{> 'daggerheart.inventory-items'
|
||||||
title=category.title
|
title=category.title
|
||||||
type='feature'
|
type='feature'
|
||||||
|
actorType='character'
|
||||||
collection=category.values
|
collection=category.values
|
||||||
canCreate=true
|
canCreate=true
|
||||||
showActions=true
|
showActions=true
|
||||||
|
|
@ -14,6 +15,7 @@
|
||||||
{{> 'daggerheart.inventory-items'
|
{{> 'daggerheart.inventory-items'
|
||||||
title=category.title
|
title=category.title
|
||||||
type='feature'
|
type='feature'
|
||||||
|
actorType='character'
|
||||||
collection=category.values
|
collection=category.values
|
||||||
canCreate=false
|
canCreate=false
|
||||||
showActions=true
|
showActions=true
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="character-row">
|
<div class="character-row">
|
||||||
|
<div class="resource-section">
|
||||||
<div class="hope-section">
|
<div class="hope-section">
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.hope"}}</h4>
|
<h4>{{localize "DAGGERHEART.GENERAL.hope"}}</h4>
|
||||||
{{#times document.system.resources.hope.max}}
|
{{#times document.system.resources.hope.max}}
|
||||||
|
|
@ -81,6 +82,8 @@
|
||||||
<i class='fa-regular fa-ban'></i>
|
<i class='fa-regular fa-ban'></i>
|
||||||
</span>
|
</span>
|
||||||
{{/times}}
|
{{/times}}
|
||||||
|
{{#if hasExtraResources}}<a type="button" class="resource-manager" data-action="toggleResourceManagement"><i class="fa-solid fa-angle-down"></i></a>{{/if}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if document.system.class.value}}
|
{{#if document.system.class.value}}
|
||||||
<div class="domains-section">
|
<div class="domains-section">
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ Parameters:
|
||||||
<legend>
|
<legend>
|
||||||
{{localize title}}
|
{{localize title}}
|
||||||
{{#if canCreate}}
|
{{#if canCreate}}
|
||||||
<a data-action="{{ifThen (or (eq type 'effect') (eq type 'feature') (eq type 'action')) 'createDoc' 'addNewItem' }}" data-document-class="{{ifThen (eq type 'effect') 'ActiveEffect' 'Item' }}"
|
<a data-action="{{ifThen (or (eq type 'effect') (and (eq type 'feature') (not (eq actorType 'character'))) (eq type 'action')) 'createDoc' 'addNewItem' }}" data-document-class="{{ifThen (eq type 'effect') 'ActiveEffect' 'Item' }}"
|
||||||
data-type="{{ifThen (eq type 'effect') 'base' type}}"
|
data-type="{{ifThen (eq type 'effect') 'base' type}}"
|
||||||
{{#if inVault}}data-in-vault="{{inVault}}"{{/if}}
|
{{#if inVault}}data-in-vault="{{inVault}}"{{/if}}
|
||||||
{{#if disabled}} data-disabled="{{disabled}}"{{/if}}
|
{{#if disabled}} data-disabled="{{disabled}}"{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -45,16 +45,8 @@ Parameters:
|
||||||
<span class="item-name">{{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span>
|
<span class="item-name">{{localize item.name}} {{#unless (or noExtensible (not item.system.description))}}<span class="expanded-icon"><i class="fa-solid fa-expand"></i></span>{{/unless}}</span>
|
||||||
|
|
||||||
{{!-- Tags Start --}}
|
{{!-- Tags Start --}}
|
||||||
{{#with item}}
|
|
||||||
{{#if (not ../hideTags)}}
|
{{#if (not ../hideTags)}}
|
||||||
<div class="item-tags">
|
{{#> "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs" item }}
|
||||||
{{#each this._getTags as |tag|}}
|
|
||||||
<div class="tag">
|
|
||||||
{{tag}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
|
|
||||||
{{!-- Feature Form Tag Start --}}
|
|
||||||
{{#if (eq ../type 'feature')}}
|
{{#if (eq ../type 'feature')}}
|
||||||
{{#if (or (eq @root.document.type 'adversary') (eq @root.document.type 'environment'))}}
|
{{#if (or (eq @root.document.type 'adversary') (eq @root.document.type 'environment'))}}
|
||||||
{{#if system.featureForm}}
|
{{#if system.featureForm}}
|
||||||
|
|
@ -64,11 +56,9 @@ Parameters:
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{!-- Feature Form Tag End --}}
|
{{/ "systems/daggerheart/templates/sheets/global/partials/item-tags.hbs"}}
|
||||||
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/with}}
|
|
||||||
{{!--Tags End --}}
|
{{!--Tags End --}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
8
templates/sheets/global/partials/item-tags.hbs
Normal file
8
templates/sheets/global/partials/item-tags.hbs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<div class="item-tags">
|
||||||
|
{{#each _getTags as |tag|}}
|
||||||
|
<div class="tag">
|
||||||
|
{{tag}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
{{#if @partial-block}}{{> @partial-block}}{{/if}}
|
||||||
|
</div>
|
||||||
|
|
@ -1,19 +1,6 @@
|
||||||
<div class="item-description-outer-container">
|
<div class="item-description-outer-container">
|
||||||
<div class="two-columns">
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.ITEMS.Armor.baseThresholds.base"}}</h4>
|
|
||||||
<span>{{item.system.baseThresholds.major}}/{{item.system.baseThresholds.severe}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.ITEMS.Armor.baseScore"}}</h4>
|
|
||||||
<span>{{item.system.baseScore}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if features.length}}
|
{{#if features.length}}
|
||||||
<div class="item-description-container">
|
<div class="item-description-container">
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.features"}}</h4>
|
|
||||||
{{#each features as | feature |}}
|
{{#each features as | feature |}}
|
||||||
<div><strong>{{localize feature.label}}</strong>: {{{localize feature.description}}}</div>
|
<div><strong>{{localize feature.label}}</strong>: {{{localize feature.description}}}</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,6 @@
|
||||||
<div class="item-description-outer-container">
|
<div class="item-description-outer-container">
|
||||||
<div class="three-columns">
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.Tiers.singular"}}</h4>
|
|
||||||
<span>{{tier}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.Trait.single"}}</h4>
|
|
||||||
<span>{{trait}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.range"}}</h4>
|
|
||||||
<span>{{range}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="three-columns">
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.damage"}}</h4>
|
|
||||||
<span>{{damage}}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="item-description-container">
|
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.burden"}}</h4>
|
|
||||||
<span>{{burden}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{#if features.length}}
|
{{#if features.length}}
|
||||||
<div class="item-description-container">
|
<div class="item-description-container">
|
||||||
<h4>{{localize "DAGGERHEART.GENERAL.features"}}</h4>
|
|
||||||
{{#each features as | feature |}}
|
{{#each features as | feature |}}
|
||||||
<div><strong>{{localize feature.label}}</strong>: {{{localize feature.description}}}</div>
|
<div><strong>{{localize feature.label}}</strong>: {{{localize feature.description}}}</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<div class="roll-part target-section dice-roll" data-action="expandRoll">
|
<div class="roll-part target-section dice-roll" data-action="expandRoll">
|
||||||
<div class="roll-part-header"><div><span>{{pluralize currentTargets.length "DAGGERHEART.GENERAL.Target"}}</span></div></div>
|
<div class="roll-part-header"><div><span>{{pluralize currentTargets.length "DAGGERHEART.GENERAL.Target"}}</span></div></div>
|
||||||
{{#if isGM}}
|
{{#if (or isGM (not metagamingSettings.hideObserverPermissionInChat))}}
|
||||||
<div class="roll-part-extra on-reduced">
|
<div class="roll-part-extra on-reduced">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
{{#if (or (gt targetShort.hit 0) (gt targetShort.miss 0))}}
|
{{#if (or (gt targetShort.hit 0) (gt targetShort.miss 0))}}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item-desc extensible">
|
<div class="item-desc extensible">
|
||||||
<span class="wrapper">{{{system.enrichedDescription}}}</span>
|
<span class="wrapper">
|
||||||
|
{{{system.enrichedTags}}}
|
||||||
|
{{{system.enrichedDescription}}}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<i class="fa-solid fa-bolt"></i>
|
<i class="fa-solid fa-bolt"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="item-icon">
|
<span class="item-icon">
|
||||||
{{#with (lookup config.DOMAIN.domains item.system.domain) as | domain |}}
|
{{#with (lookup allDomains item.system.domain) as | domain |}}
|
||||||
<img src="{{domain.src}}" alt="">
|
<img src="{{domain.src}}" alt="">
|
||||||
{{/with}}
|
{{/with}}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
21
templates/ui/tooltip/resourceManagement.hbs
Normal file
21
templates/ui/tooltip/resourceManagement.hbs
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<div class="daggerheart resource-management-container">
|
||||||
|
{{#each resources as |resource|}}
|
||||||
|
<div class="resource-section {{resource.resourceClass}}">
|
||||||
|
<h4>{{resource.label}}</h4>
|
||||||
|
{{#times resource.max}}
|
||||||
|
<span class='resource-value' data-action='toggleResource' data-value="{{add this 1}}" data-resource="{{resource.id}}">
|
||||||
|
{{#if resource.fullIcon.isIcon}}
|
||||||
|
<i class='{{resource.fullIcon.value}} full {{#unless (gte ../value (add this 1))}}hidden{{/unless}}'></i>
|
||||||
|
{{else}}
|
||||||
|
<img src="{{resource.fullIcon.value}}" class="full {{#unless resource.fullIcon.noColorFilter}}filter{{else}}non-transparent{{/unless}} {{#unless (gte ../value (add this 1))}}hidden{{/unless}}" />
|
||||||
|
{{/if}}
|
||||||
|
{{#if resource.emptyIcon.isIcon}}
|
||||||
|
<i class='{{resource.emptyIcon.value}} empty {{#if (gte ../value (add this 1))}}hidden{{/if}}'></i>
|
||||||
|
{{else}}
|
||||||
|
<img src="{{resource.emptyIcon.value}}" class="empty {{#unless resource.fullIcon.noColorFilter}}filter{{else}}non-transparent{{/unless}} {{#if (gte ../value (add this 1))}}hidden{{/if}}" />
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
{{/times}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue