mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-06-08 21:58:11 +02:00
Compare commits
No commits in common. "abd7824c967681f6752010c3c81f356cb7857a70" and "85ca7efc6de317ca52c30fbea50531a8f917f90a" have entirely different histories.
abd7824c96
...
85ca7efc6d
36 changed files with 348 additions and 540 deletions
14
lang/en.json
14
lang/en.json
|
|
@ -2442,7 +2442,6 @@
|
||||||
"single": "Miss",
|
"single": "Miss",
|
||||||
"plural": "Miss"
|
"plural": "Miss"
|
||||||
},
|
},
|
||||||
"missingX": "Missing {x}",
|
|
||||||
"maxWithThing": "Max {thing}",
|
"maxWithThing": "Max {thing}",
|
||||||
"missingDragDropThing": "Drop {thing} here",
|
"missingDragDropThing": "Drop {thing} here",
|
||||||
"multiclass": "Multiclass",
|
"multiclass": "Multiclass",
|
||||||
|
|
@ -2533,9 +2532,6 @@
|
||||||
"recovery": { "label": "Recovery" },
|
"recovery": { "label": "Recovery" },
|
||||||
"type": { "label": "Type" },
|
"type": { "label": "Type" },
|
||||||
"value": { "label": "Value" }
|
"value": { "label": "Value" }
|
||||||
},
|
|
||||||
"identifier": {
|
|
||||||
"label": "Identifier"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Ancestry": {
|
"Ancestry": {
|
||||||
|
|
@ -2826,15 +2822,6 @@
|
||||||
"hideObserverPermissionInChat": {
|
"hideObserverPermissionInChat": {
|
||||||
"label": "Hide Chat Info From Players",
|
"label": "Hide Chat Info From Players",
|
||||||
"hint": "Information such as hit/miss on attack rolls against adversaries will be hidden"
|
"hint": "Information such as hit/miss on attack rolls against adversaries will be hidden"
|
||||||
},
|
|
||||||
"hidePartyStats": {
|
|
||||||
"label": "Hide Party Stats",
|
|
||||||
"hint": "Resources and stats in the party sheet's member list will be hidden to the following users, even if the user is part of the same party",
|
|
||||||
"choices": {
|
|
||||||
"never": "Never, always show",
|
|
||||||
"players": "Hide From Players",
|
|
||||||
"always": "Hide from Everyone"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -3223,6 +3210,7 @@
|
||||||
"subclassesAlreadyPresent": "You already have a class and multiclass subclass",
|
"subclassesAlreadyPresent": "You already have a class and multiclass subclass",
|
||||||
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice",
|
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice",
|
||||||
"gmMenuRefresh": "You refreshed all actions and resources {types}",
|
"gmMenuRefresh": "You refreshed all actions and resources {types}",
|
||||||
|
"subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.",
|
||||||
"gmRequired": "This action requires an online GM",
|
"gmRequired": "This action requires an online GM",
|
||||||
"gmOnly": "This can only be accessed by the GM",
|
"gmOnly": "This can only be accessed by the GM",
|
||||||
"noActorOwnership": "You do not have permissions for this character",
|
"noActorOwnership": "You do not have permissions for this character",
|
||||||
|
|
|
||||||
|
|
@ -439,13 +439,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null }
|
'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (type === 'subclasses') {
|
if (type === 'subclasses')
|
||||||
const classItem = this.setup.class;
|
|
||||||
const uuid = classItem?._stats.compendiumSource ?? classItem?.uuid;
|
|
||||||
presets.filter = {
|
presets.filter = {
|
||||||
'system.linkedClass': { key: 'system.linkedClass', value: uuid }
|
'system.linkedClass.uuid': { key: 'system.linkedClass.uuid', value: this.setup.class?.uuid }
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (equipment.includes(type))
|
if (equipment.includes(type))
|
||||||
presets.filter = {
|
presets.filter = {
|
||||||
|
|
@ -613,8 +610,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
|
||||||
[foundry.utils.randomID()]: {}
|
[foundry.utils.randomID()]: {}
|
||||||
};
|
};
|
||||||
} else if (item.type === 'subclass' && event.target.closest('.subclass-card')) {
|
} else if (item.type === 'subclass' && event.target.closest('.subclass-card')) {
|
||||||
const classSubclasses = await this.setup.class.system.fetchSubclasses();
|
if (this.setup.class.system.subclasses.every(subclass => subclass.uuid !== item.uuid)) {
|
||||||
if (classSubclasses.every(subclass => subclass.uuid !== item.uuid)) {
|
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,9 +209,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
context.attributes = Object.keys(this.document.system.traits).reduce((acc, key) => {
|
context.attributes = Object.keys(this.document.system.traits).reduce((acc, key) => {
|
||||||
acc[key] = {
|
acc[key] = {
|
||||||
...this.document.system.traits[key],
|
...this.document.system.traits[key],
|
||||||
label: _loc(CONFIG.DH.ACTOR.abilities[key].label),
|
name: game.i18n.localize(CONFIG.DH.ACTOR.abilities[key].name),
|
||||||
verbs: CONFIG.DH.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x)),
|
verbs: CONFIG.DH.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x))
|
||||||
isSpellcasting: this.document.system.spellcastModifierTrait?.key === key
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
|
|
@ -228,7 +227,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0;
|
context.resources.stress.max < maxResource ? maxResource - context.resources.stress.max : 0;
|
||||||
|
|
||||||
context.equippedItems = sortBy(
|
context.equippedItems = sortBy(
|
||||||
this.document.items.filter(i => i.system.equipped && (i.type === 'weapon' || i.usable)),
|
this.document.items.filter(i => i.system.equipped),
|
||||||
i => (i.type === 'weapon' ? (i.system.secondary ? 1 : 0) : 2)
|
i => (i.type === 'weapon' ? (i.system.secondary ? 1 : 0) : 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,14 +85,6 @@ export default class Party extends DHBaseActorSheet {
|
||||||
/* Prepare Context */
|
/* Prepare Context */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
async _prepareContext(options) {
|
|
||||||
const context = await super._prepareContext(options);
|
|
||||||
const settings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming);
|
|
||||||
context.showStats =
|
|
||||||
settings.hidePartyStats === 'never' || (settings.hidePartyStats === 'players' && game.user.isGM);
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
||||||
|
|
@ -104,10 +104,9 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _prepareContext(options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(options);
|
const context = await super._prepareContext(_options);
|
||||||
context.domains = this.document.system.domains;
|
context.domains = this.document.system.domains;
|
||||||
context.subclasses = await this.document.system.fetchSubclasses();
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,8 +128,20 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
const item = await fromUuid(data.uuid);
|
const item = await fromUuid(data.uuid);
|
||||||
const itemType = data.type === 'ActiveEffect' ? data.type : item.type;
|
const itemType = data.type === 'ActiveEffect' ? data.type : item.type;
|
||||||
const target = event.target.closest('fieldset.drop-section');
|
const target = event.target.closest('fieldset.drop-section');
|
||||||
|
if (itemType === 'subclass') {
|
||||||
if (['feature', 'ActiveEffect'].includes(itemType)) {
|
if (item.system.linkedClass) {
|
||||||
|
return ui.notifications.warn(
|
||||||
|
game.i18n.format('DAGGERHEART.UI.Notifications.subclassAlreadyLinked', {
|
||||||
|
name: item.name,
|
||||||
|
class: this.document.name
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await item.update({ 'system.linkedClass': this.document.uuid });
|
||||||
|
await this.document.update({
|
||||||
|
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
|
||||||
|
});
|
||||||
|
} else if (['feature', 'ActiveEffect'].includes(itemType)) {
|
||||||
super._onDrop(event);
|
super._onDrop(event);
|
||||||
} else if (this.document.parent?.type !== 'character') {
|
} else if (this.document.parent?.type !== 'character') {
|
||||||
if (itemType === 'weapon') {
|
if (itemType === 'weapon') {
|
||||||
|
|
@ -189,6 +200,12 @@ export default class ClassSheet extends DHBaseItemSheet {
|
||||||
static async #removeItemFromCollection(_event, element) {
|
static async #removeItemFromCollection(_event, element) {
|
||||||
const { uuid, target } = element.dataset;
|
const { uuid, target } = element.dataset;
|
||||||
const prop = foundry.utils.getProperty(this.document.system, target);
|
const prop = foundry.utils.getProperty(this.document.system, target);
|
||||||
|
|
||||||
|
if (target === 'subclasses') {
|
||||||
|
const subclass = await foundry.utils.fromUuid(uuid);
|
||||||
|
await subclass?.update({ 'system.linkedClass': null });
|
||||||
|
}
|
||||||
|
|
||||||
await this.document.update({ [`system.${target}`]: prop.filter(i => i && i.uuid !== uuid).map(x => x.uuid) });
|
await this.document.update({ [`system.${target}`]: prop.filter(i => i && i.uuid !== uuid).map(x => x.uuid) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,36 +40,4 @@ export default class SubclassSheet extends DHBaseItemSheet {
|
||||||
get relatedDocs() {
|
get relatedDocs() {
|
||||||
return this.document.system.features.map(x => x.item);
|
return this.document.system.features.map(x => x.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _prepareContext(options) {
|
|
||||||
const context = await super._prepareContext(options);
|
|
||||||
if (this.document.system.linkedClass) {
|
|
||||||
const classData = await fromUuid(this.document.system.linkedClass);
|
|
||||||
context.class = classData ?? {
|
|
||||||
name: _loc('DAGGERHEART.GENERAL.missingX', { x: _loc('TYPES.Item.class') }),
|
|
||||||
missing: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDrop(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const data = TextEditor.getDragEventData(event);
|
|
||||||
const item = await fromUuid(data.uuid);
|
|
||||||
const itemType = data.type === 'ActiveEffect' ? data.type : item.type;
|
|
||||||
if (itemType === 'class') {
|
|
||||||
const uuid = item._stats.compendiumSource ?? item.uuid;
|
|
||||||
if (this.document.system.linkedClass !== uuid) {
|
|
||||||
await this.document.update({ 'system.linkedClass': uuid });
|
|
||||||
// Re-render all class sheets for instant feedback
|
|
||||||
for (const app of foundry.applications.instances.values()) {
|
|
||||||
if (app.document?.type === 'class') app.render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return super._onDrop(event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
(await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description));
|
(await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fieldFilter = await this._createFieldFilter();
|
this.fieldFilter = this._createFieldFilter();
|
||||||
|
|
||||||
if (this.presets?.filter) {
|
if (this.presets?.filter) {
|
||||||
Object.entries(this.presets.filter).forEach(([k, v]) => {
|
Object.entries(this.presets.filter).forEach(([k, v]) => {
|
||||||
|
|
@ -355,12 +355,12 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _createFieldFilter() {
|
_createFieldFilter() {
|
||||||
const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters');
|
const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters');
|
||||||
for (const f of filters) {
|
filters.forEach(f => {
|
||||||
if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field);
|
if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field);
|
||||||
else if (typeof f.choices === 'function') {
|
else if (typeof f.choices === 'function') {
|
||||||
f.choices = await f.choices(this.items);
|
f.choices = f.choices(this.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear field label so template uses our custom label parameter
|
// Clear field label so template uses our custom label parameter
|
||||||
|
|
@ -370,8 +370,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
|
||||||
f.name ??= f.key;
|
f.name ??= f.key;
|
||||||
f.value = this.presets?.filter?.[f.name]?.value ?? null;
|
f.value = this.presets?.filter?.[f.name]?.value ?? null;
|
||||||
}
|
});
|
||||||
|
|
||||||
return filters;
|
return filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -383,8 +383,7 @@ export const typeConfig = {
|
||||||
{
|
{
|
||||||
key: 'system.linkedClass',
|
key: 'system.linkedClass',
|
||||||
label: 'TYPES.Item.class',
|
label: 'TYPES.Item.class',
|
||||||
format: linkedClass =>
|
format: linkedClass => linkedClass?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing'
|
||||||
foundry.utils.fromUuidSync(linkedClass)?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing'
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'system.spellcastingTrait',
|
key: 'system.spellcastingTrait',
|
||||||
|
|
@ -394,18 +393,15 @@ export const typeConfig = {
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'system.linkedClass',
|
key: 'system.linkedClass.uuid',
|
||||||
label: 'TYPES.Item.class',
|
label: 'TYPES.Item.class',
|
||||||
choices: async items => {
|
choices: items => {
|
||||||
const list = [];
|
const list = items
|
||||||
for (const item of items.filter(item => item.system.linkedClass)) {
|
.filter(item => item.system.linkedClass)
|
||||||
const linkedClass = await foundry.utils.fromUuid(item.system.linkedClass);
|
.map(item => ({
|
||||||
list.push({
|
value: item.system.linkedClass.uuid,
|
||||||
value: linkedClass.uuid,
|
label: item.system.linkedClass.name
|
||||||
label: linkedClass.name
|
}));
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return list.reduce((a, c) => {
|
return list.reduce((a, c) => {
|
||||||
if (!a.find(i => i.value === c.value)) a.push(c);
|
if (!a.find(i => i.value === c.value)) a.push(c);
|
||||||
return a;
|
return a;
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
||||||
const features = [];
|
const features = [];
|
||||||
for (let f of this.features) {
|
for (let f of this.features) {
|
||||||
const fBase = f.item ?? f;
|
const fBase = f.item ?? f;
|
||||||
const feature = fBase.pack ? await foundry.utils.fromUuid(fBase.uuid) : fBase;
|
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
||||||
features.push(
|
features.push(
|
||||||
foundry.utils.mergeObject(
|
foundry.utils.mergeObject(
|
||||||
feature.toObject(),
|
feature.toObject(),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export default class DHClass extends BaseDataItem {
|
||||||
}),
|
}),
|
||||||
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
|
||||||
features: new ItemLinkFields(),
|
features: new ItemLinkFields(),
|
||||||
|
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
inventory: new fields.SchemaField({
|
inventory: new fields.SchemaField({
|
||||||
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
choiceA: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
choiceA: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
|
||||||
|
|
@ -69,24 +70,6 @@ export default class DHClass extends BaseDataItem {
|
||||||
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item);
|
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchSubclasses() {
|
|
||||||
const uuids = [this.parent.uuid, this.parent._stats?.compendiumSource].filter(u => !!u);
|
|
||||||
const subclasses = game.items.filter(x => x.type === 'subclass' && uuids.includes(x.system.linkedClass));
|
|
||||||
for (const pack of game.packs) {
|
|
||||||
const indexes = await pack.getIndex({ fields: ['system.linkedClass'] });
|
|
||||||
for (const index of indexes) {
|
|
||||||
if (index.type !== 'subclass') continue;
|
|
||||||
if (!uuids.includes(index.system?.linkedClass)) continue;
|
|
||||||
if (subclasses.find(x => x.uuid === index.uuid)) continue;
|
|
||||||
|
|
||||||
const subclass = await foundry.utils.fromUuid(index.uuid);
|
|
||||||
subclasses.push(subclass);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return subclasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
async _preCreate(data, options, user) {
|
||||||
if (this.actor?.type === 'character') {
|
if (this.actor?.type === 'character') {
|
||||||
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
|
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
features: new ItemLinkFields(),
|
features: new ItemLinkFields(),
|
||||||
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
|
||||||
isMulticlass: new fields.BooleanField({ initial: false }),
|
isMulticlass: new fields.BooleanField({ initial: false }),
|
||||||
linkedClass: new fields.DocumentUUIDField({ type: 'Item', nullable: true, initial: null })
|
linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,8 +83,7 @@ export default class DHSubclass extends BaseDataItem {
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (actorClass.system.subclasses.every(x => x.uuid !== dataUuid)) {
|
||||||
if ((await actorClass.system.fetchSubclasses()).every(x => x.uuid !== dataUuid)) {
|
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { defaultRestOptions } from '../../config/generalConfig.mjs';
|
import { defaultRestOptions } from '../../config/generalConfig.mjs';
|
||||||
import { resetAndRerenderActors } from '../../helpers/utils.mjs';
|
|
||||||
import { ActionsField } from '../fields/actionField.mjs';
|
import { ActionsField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
const currencyField = (initial, label, icon) =>
|
const currencyField = (initial, label, icon) =>
|
||||||
|
|
@ -210,7 +209,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refreshConfig();
|
this.refreshConfig();
|
||||||
resetAndRerenderActors();
|
this.#resetActors();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update config values based on homebrew data. Make sure the references don't change */
|
/** Update config values based on homebrew data. Make sure the references don't change */
|
||||||
|
|
@ -231,6 +230,29 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
export class Resource extends foundry.abstract.DataModel {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { resetAndRerenderActors } from '../../helpers/utils.mjs';
|
|
||||||
|
|
||||||
export default class DhMetagaming extends foundry.abstract.DataModel {
|
export default class DhMetagaming extends foundry.abstract.DataModel {
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
@ -8,24 +6,7 @@ export default class DhMetagaming extends foundry.abstract.DataModel {
|
||||||
initial: false,
|
initial: false,
|
||||||
label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.label',
|
label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.label',
|
||||||
hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.hint'
|
hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hideObserverPermissionInChat.hint'
|
||||||
}),
|
|
||||||
hidePartyStats: new fields.StringField({
|
|
||||||
initial: 'never',
|
|
||||||
label: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.label',
|
|
||||||
hint: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.hint',
|
|
||||||
required: true,
|
|
||||||
nullable: false,
|
|
||||||
choices: {
|
|
||||||
never: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.never',
|
|
||||||
players: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.players',
|
|
||||||
always: 'DAGGERHEART.SETTINGS.Metagaming.FIELDS.hidePartyStats.choices.always'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Invoked by the setting when data changes */
|
|
||||||
handleChange() {
|
|
||||||
resetAndRerenderActors();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,8 @@ export default class DHRoll extends Roll {
|
||||||
const metagamingSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming);
|
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, {
|
return foundry.applications.handlebars.renderTemplate(template, {
|
||||||
roll: this,
|
|
||||||
...chatData,
|
...chatData,
|
||||||
|
roll: this,
|
||||||
parent: chatData.parent,
|
parent: chatData.parent,
|
||||||
targetMode: chatData.targetMode,
|
targetMode: chatData.targetMode,
|
||||||
areas: chatData.action?.areas,
|
areas: chatData.action?.areas,
|
||||||
|
|
|
||||||
|
|
@ -793,26 +793,6 @@ export function getArmorSources(actor) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
export function resetAndRerenderActors() {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array sorted by a function that returns a thing to compare, or an array to compare in order
|
* Returns an array sorted by a function that returns a thing to compare, or an array to compare in order
|
||||||
* Similar to lodash's sortBy function.
|
* Similar to lodash's sortBy function.
|
||||||
|
|
@ -861,11 +841,3 @@ export function createShallowProxy(obj) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function camelize(str) {
|
|
||||||
return str
|
|
||||||
.replace(/(?:^\w|[A-Z]|\b\w)/g, (part, index) => {
|
|
||||||
return index === 0 ? part.toLowerCase() : part.toUpperCase();
|
|
||||||
})
|
|
||||||
.replace(/\s+/g, '');
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -91,10 +91,7 @@ const registerMenuSettings = () => {
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Metagaming, {
|
||||||
scope: 'world',
|
scope: 'world',
|
||||||
config: false,
|
config: false,
|
||||||
type: DhMetagaming,
|
type: DhMetagaming
|
||||||
onChange: value => {
|
|
||||||
value.handleChange();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, {
|
game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, {
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,8 @@
|
||||||
|
|
||||||
a:hover,
|
a:hover,
|
||||||
a.active {
|
a.active {
|
||||||
text-shadow: 0 0 1px currentColor, 0 0 1px currentColor, 0 0 8px light-dark(@dark-blue, @golden);
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 8px light-dark(@dark-blue, @golden);
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.feature-line {
|
.feature-line {
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -35,14 +34,6 @@
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
.image-icon {
|
|
||||||
font-size: 26px;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.controls {
|
.controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -55,3 +46,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,20 @@
|
||||||
// Theme header backgrounds
|
// Theme header backgrounds
|
||||||
.appTheme({
|
.appTheme({
|
||||||
.character-header-sheet {
|
.character-header-sheet {
|
||||||
|
.trait {
|
||||||
|
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
.character-row .domains-section img {
|
.character-row .domains-section img {
|
||||||
filter: @golden-filter;
|
filter: @golden-filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
.character-header-sheet {
|
.character-header-sheet {
|
||||||
|
.trait {
|
||||||
|
background: url('../assets/svg/trait-shield-light.svg') no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
.character-row .domains-section img {
|
.character-row .domains-section img {
|
||||||
filter: brightness(0) saturate(100%);
|
filter: brightness(0) saturate(100%);
|
||||||
}
|
}
|
||||||
|
|
@ -25,19 +33,13 @@
|
||||||
|
|
||||||
.name-row {
|
.name-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 6px;
|
gap: 5px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
[contenteditable],
|
|
||||||
input {
|
|
||||||
border: 1px solid @soft-shadow;
|
|
||||||
background-color: light-dark(@dark-15, @soft-white-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -63,16 +65,14 @@
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
border: none;
|
|
||||||
width: 40px;
|
width: 40px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 600;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.level-button {
|
.level-button {
|
||||||
|
|
@ -101,7 +101,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 10px;
|
||||||
font-size: var(--font-size-12);
|
font-size: var(--font-size-12);
|
||||||
color: light-dark(@dark-blue, @golden);
|
color: light-dark(@dark-blue, @golden);
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 15px;
|
||||||
|
|
||||||
.resource-section {
|
.resource-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -168,7 +168,7 @@
|
||||||
.domains-section {
|
.domains-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 4px;
|
gap: 10px;
|
||||||
background-color: light-dark(transparent, @dark-blue);
|
background-color: light-dark(transparent, @dark-blue);
|
||||||
color: light-dark(@dark-blue, @golden);
|
color: light-dark(@dark-blue, @golden);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
|
|
@ -183,7 +183,6 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: light-dark(@dark-blue, @golden);
|
color: light-dark(@dark-blue, @golden);
|
||||||
margin-right: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.domain {
|
.domain {
|
||||||
|
|
@ -218,110 +217,37 @@
|
||||||
|
|
||||||
.character-traits {
|
.character-traits {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
justify-content: space-between;
|
|
||||||
max-width: 38.5rem;
|
|
||||||
gap: 0.5rem;
|
|
||||||
padding-left: 0.5rem;
|
|
||||||
|
|
||||||
.trait {
|
.trait {
|
||||||
--color-border: light-dark(@semi-transparent-dark-blue, @golden-60);
|
height: 60px;
|
||||||
|
width: 60px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
min-width: 4.375rem;
|
|
||||||
|
|
||||||
.trait-name {
|
.trait-name {
|
||||||
position: relative;
|
display: flex;
|
||||||
background-color: light-dark(@semi-transparent-dark-blue, @golden-40);
|
align-items: center;
|
||||||
border: 1px solid var(--color-border);
|
padding-top: 5px;
|
||||||
border-radius: 3px;
|
color: light-dark(@dark-blue, @golden);
|
||||||
color: light-dark(var(--color-light-1), @golden);
|
font-size: var(--font-size-14);
|
||||||
font-size: var(--font-size-12);
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
height: 1rem;
|
|
||||||
line-height: 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0 0.1876px 0 0.375rem;
|
|
||||||
margin-right: 0.125rem; /* makes it center SLIGHTLY */
|
|
||||||
text-shadow: 1px 1px 2px @light-black;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
gap: 3px;
|
||||||
|
|
||||||
.tier-mark {
|
i {
|
||||||
position: absolute;
|
line-height: 17px;
|
||||||
background-color: @dark-blue;
|
font-size: var(--font-size-10);
|
||||||
border: 1px solid light-dark(@dark-blue, @golden);
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 1rem;
|
|
||||||
height: 1rem;
|
|
||||||
right: calc(100% - 0.4375rem);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
&.marked::before {
|
|
||||||
content: ' ';
|
|
||||||
position: absolute;
|
|
||||||
width: 0.5rem;
|
|
||||||
height: 0.5rem;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: @golden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.trait-value-area {
|
|
||||||
--background: light-dark(#e8e6e3, @dark-blue);
|
|
||||||
display: flex;
|
|
||||||
position: relative;
|
|
||||||
.trait-value {
|
.trait-value {
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
justify-content: center;
|
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 400;
|
||||||
font-size: var(--font-size-20);
|
font-size: var(--font-size-20);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 0.375rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spellcasting-mark {
|
|
||||||
position: absolute;
|
|
||||||
border: 1px solid light-dark(@dark-blue, @golden);
|
|
||||||
color: @golden;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: -0.375rem;
|
|
||||||
margin-inline: auto;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 1.125rem;
|
|
||||||
height: 1.125rem;
|
|
||||||
background: radial-gradient(190.63% 190.63% at 50% -80.63%, #18152E 70%, #4D4494 80%, #A0837E 90%, var(--color-border) 100%);
|
|
||||||
font-size: var(--font-size-9);
|
|
||||||
text-shadow: 0 0 2px @light-black;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.trait-name {
|
|
||||||
color: light-dark(@dark, @beige);
|
|
||||||
text-shadow: 0 0 8px light-dark(@dark-80, @beige-80);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,62 @@
|
||||||
.death-roll-btn {
|
.death-roll-btn {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icons-list {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
align-items: end;
|
||||||
|
justify-content: center;
|
||||||
|
top: 45px;
|
||||||
|
right: 10px;
|
||||||
|
|
||||||
|
.spellcast-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: end;
|
||||||
|
text-align: center;
|
||||||
|
padding-right: 8px;
|
||||||
|
max-width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
background: light-dark(@dark-blue-60, @dark-golden-80);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
border: 4px double light-dark(@beige, @golden);
|
||||||
|
color: light-dark(@beige, @golden);
|
||||||
|
border-radius: 999px;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
.spellcast-label {
|
||||||
|
font-size: var(--font-size-14);
|
||||||
|
opacity: 0;
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
align-content: center;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.no-label):hover {
|
||||||
|
max-width: 300px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-radius: 60px;
|
||||||
|
|
||||||
|
.spellcast-label {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info-section {
|
.info-section {
|
||||||
|
|
|
||||||
|
|
@ -280,17 +280,6 @@ body.game:is(.performance-low, .noblur) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.actors-list.limited {
|
|
||||||
.actor-resources {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.actor-img-frame {
|
|
||||||
width: 3rem;
|
|
||||||
height: 3rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.actors-dragger {
|
.actors-dragger {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,4 @@
|
||||||
font-family: @font-body;
|
font-family: @font-body;
|
||||||
color: light-dark(@chat-blue-bg, @beige-50);
|
color: light-dark(@chat-blue-bg, @beige-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
button.plain.inline-control {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
--golden: #f3c267;
|
--golden: #f3c267;
|
||||||
--golden-10: #f3c26710;
|
--golden-10: #f3c26710;
|
||||||
--golden-40: #f3c26740;
|
--golden-40: #f3c26740;
|
||||||
--golden-60: #f3c26760;
|
|
||||||
--golden-90: #f3c26790;
|
--golden-90: #f3c26790;
|
||||||
--golden-bg: #f3c2671a;
|
--golden-bg: #f3c2671a;
|
||||||
--golden-secondary: #eaaf42;
|
--golden-secondary: #eaaf42;
|
||||||
|
|
@ -90,7 +89,6 @@
|
||||||
@golden: var(--golden, #f3c267);
|
@golden: var(--golden, #f3c267);
|
||||||
@golden-10: var(--golden-10, #f3c26710);
|
@golden-10: var(--golden-10, #f3c26710);
|
||||||
@golden-40: var(--golden-40, #f3c26740);
|
@golden-40: var(--golden-40, #f3c26740);
|
||||||
@golden-60: var(--golden-60, #f3c26760);
|
|
||||||
@golden-90: var(--golden-90, #f3c26790);
|
@golden-90: var(--golden-90, #f3c26790);
|
||||||
@golden-bg: var(--golden-bg, #f3c2671a);
|
@golden-bg: var(--golden-bg, #f3c2671a);
|
||||||
@golden-secondary: var(--golden-secondary, #eaaf42);
|
@golden-secondary: var(--golden-secondary, #eaaf42);
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,6 @@
|
||||||
--dh-font-title: 'Cinzel Decorative';
|
--dh-font-title: 'Cinzel Decorative';
|
||||||
--dh-font-subtitle: 'Cinzel';
|
--dh-font-subtitle: 'Cinzel';
|
||||||
--dh-font-body: 'Montserrat';
|
--dh-font-body: 'Montserrat';
|
||||||
|
|
||||||
/* Include missing font sizes */
|
|
||||||
--font-size-8: 0.5rem;
|
|
||||||
--font-size-9: 0.5625rem;
|
|
||||||
--font-size-22: 1.375rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-title: ~"var(--dh-font-title, 'Cinzel Decorative'), serif";
|
@font-title: ~"var(--dh-font-title, 'Cinzel Decorative'), serif";
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
"id": "daggerheart",
|
"id": "daggerheart",
|
||||||
"title": "Daggerheart",
|
"title": "Daggerheart",
|
||||||
"description": "An unofficial implementation of the Daggerheart system",
|
"description": "An unofficial implementation of the Daggerheart system",
|
||||||
"version": "2.2.4",
|
"version": "2.2.3",
|
||||||
"compatibility": {
|
"compatibility": {
|
||||||
"minimum": "14.359",
|
"minimum": "14.359",
|
||||||
"verified": "14.361",
|
"verified": "14.360",
|
||||||
"maximum": "14"
|
"maximum": "14"
|
||||||
},
|
},
|
||||||
"url": "https://github.com/Foundryborne/daggerheart",
|
"url": "https://github.com/Foundryborne/daggerheart",
|
||||||
"manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json",
|
"manifest": "https://raw.githubusercontent.com/Foundryborne/daggerheart/v14/system.json",
|
||||||
"download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.4/system.zip",
|
"download": "https://github.com/Foundryborne/daggerheart/releases/download/2.2.3/system.zip",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "WBHarry"
|
"name": "WBHarry"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
<div>
|
<div>
|
||||||
{{formGroup settingFields.schema.fields.hideObserverPermissionInChat value=settingFields._source.hideObserverPermissionInChat localize=true}}
|
{{formGroup settingFields.schema.fields.hideObserverPermissionInChat value=settingFields._source.hideObserverPermissionInChat localize=true}}
|
||||||
{{formGroup settingFields.schema.fields.hidePartyStats value=settingFields._source.hidePartyStats localize=true}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
<header class='adversary-header-sheet'>
|
<header class='adversary-header-sheet'>
|
||||||
<line-div></line-div>
|
<line-div></line-div>
|
||||||
<div class="name-row">
|
<div class="name-row">
|
||||||
<h1
|
<h1 class='input actor-name' contenteditable="plaintext-only" data-property="name" placeholder="{{localize "DAGGERHEART.GENERAL.actorName"}}">{{source.name}}</h1>
|
||||||
class="input actor-name"
|
|
||||||
contenteditable="plaintext-only"
|
|
||||||
data-property="name"
|
|
||||||
placeholder="{{localize "DAGGERHEART.GENERAL.actorName"}}"
|
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
>{{source.name}}</h1>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tags">
|
<div class="tags">
|
||||||
<div class="tag">
|
<div class="tag">
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,7 @@
|
||||||
<header class="character-header-sheet">
|
<header class="character-header-sheet">
|
||||||
<line-div></line-div>
|
<line-div></line-div>
|
||||||
<div class="name-row">
|
<div class="name-row">
|
||||||
<h1
|
<h1 class="actor-name input" contenteditable="plaintext-only" data-property="name" placeholder="{{localize "DAGGERHEART.GENERAL.actorName"}}">{{source.name}}</h1>
|
||||||
class="actor-name input"
|
|
||||||
contenteditable="plaintext-only"
|
|
||||||
data-property="name"
|
|
||||||
placeholder="{{localize "DAGGERHEART.GENERAL.actorName"}}"
|
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
>{{source.name}}</h1>
|
|
||||||
<div class='level-div'>
|
<div class='level-div'>
|
||||||
<h3 class='label'>
|
<h3 class='label'>
|
||||||
{{#if @root.editable}}
|
{{#if @root.editable}}
|
||||||
|
|
@ -132,16 +125,15 @@
|
||||||
|
|
||||||
<div class="character-traits">
|
<div class="character-traits">
|
||||||
{{#each this.attributes as |attribute key|}}
|
{{#each this.attributes as |attribute key|}}
|
||||||
<div class="trait {{#if isSpellcasting}}with-spellcasting{{/if}}" data-tooltip="<b>{{attribute.label}}:</b><br>{{#each attribute.verbs}}{{this}}<br>{{/each}}" data-action="rollAttribute" data-attribute="{{key}}" data-value="{{attribute.value}}">
|
<div class="trait" data-tooltip="<b>{{localize (concat 'DAGGERHEART.CONFIG.Traits.' key '.name') }}:</b><br>{{#each attribute.verbs}}{{this}}<br>{{/each}}" data-action="rollAttribute" data-attribute="{{key}}" data-value="{{attribute.value}}">
|
||||||
<div class="trait-name">
|
<div class="trait-name">
|
||||||
<div class="tier-mark {{#if attribute.tierMarked}}marked{{/if}}"></div>
|
<span>{{localize (concat 'DAGGERHEART.CONFIG.Traits.' key '.short')}}</span>
|
||||||
<span>{{attribute.label}}</span>
|
{{#if attribute.tierMarked}}
|
||||||
|
<i class='fa-solid fa-circle'></i>
|
||||||
|
{{else}}
|
||||||
|
<i class='fa-regular fa-circle'></i>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="trait-value-area">
|
|
||||||
<svg width="52" height="46" viewBox="0 0 52 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M 0,0 H 52 L 51.0714,18.254 48.781,24.0952 47.5745,39.9596 26,46 4.42553,39.9596 3.219,24.0952 0.928571,18.254 Z" fill="var(--color-border)"/>
|
|
||||||
<path d="M 3.312,5.357 8.58596,0 H 43.414 l 5.274,5.357 -1.8797,28.846 c -0.2431,2.605 -2.1461,4.7522 -4.7031,5.3064 l -14.8343,3.2151 c -0.8375,0.1816 -1.7043,0.1816 -2.5418,0 L 9.89482,39.5094 C 7.33785,38.9552 5.43478,36.808 5.19169,34.203 Z" fill="var(--background)"/>
|
|
||||||
</svg>
|
|
||||||
<div class="trait-value">
|
<div class="trait-value">
|
||||||
{{#if (gt attribute.value 0)}}
|
{{#if (gt attribute.value 0)}}
|
||||||
<span>+{{attribute.value}}</span>
|
<span>+{{attribute.value}}</span>
|
||||||
|
|
@ -149,12 +141,6 @@
|
||||||
<span>{{attribute.value}}</span>
|
<span>{{attribute.value}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{#if isSpellcasting}}
|
|
||||||
<div class="spellcasting-mark" data-tooltip="DAGGERHEART.ITEMS.Subclass.spellcastingTrait">
|
|
||||||
<i class="fa-solid fa-wand-magic-sparkles" inert></i>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,17 @@
|
||||||
<aside class="character-sidebar-sheet">
|
<aside class="character-sidebar-sheet">
|
||||||
<div class="portrait {{#if isDeath}}death-roll{{/if}}">
|
<div class="portrait {{#if isDeath}}death-roll{{/if}}">
|
||||||
<img src="{{document.img}}" alt="{{document.name}}" data-action='editImage' data-edit="img">
|
<img src="{{document.img}}" alt="{{document.name}}" data-action='editImage' data-edit="img">
|
||||||
|
{{#if document.system.spellcastModifierTrait.key}}
|
||||||
|
<div class="icons-list">
|
||||||
|
<span class="spellcast-icon {{#if isDeath}}no-label{{/if}}">
|
||||||
|
<span class="spellcast-label">
|
||||||
|
{{localize "DAGGERHEART.ITEMS.Subclass.spellcastingTrait"}}:
|
||||||
|
{{localize (concat 'DAGGERHEART.CONFIG.Traits.' document.system.spellcastModifierTrait.key '.short')}}
|
||||||
|
</span>
|
||||||
|
<i class="fa-solid fa-wand-sparkles"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
<a class="death-roll-btn" data-tooltip="DAGGERHEART.UI.Tooltip.makeDeathMove" {{#if
|
<a class="death-roll-btn" data-tooltip="DAGGERHEART.UI.Tooltip.makeDeathMove" {{#if
|
||||||
isDeath}}data-action="makeDeathMove" {{/if}}><i class="fa-solid fa-skull death-save"></i></a>
|
isDeath}}data-action="makeDeathMove" {{/if}}><i class="fa-solid fa-skull death-save"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
name='name'
|
name='name'
|
||||||
value='{{document.name}}'
|
value='{{document.name}}'
|
||||||
placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}'
|
placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}'
|
||||||
autocomplete="off"
|
|
||||||
spellcheck="false"
|
|
||||||
/>
|
/>
|
||||||
</h1>
|
</h1>
|
||||||
{{#if useResourcePips}}
|
{{#if useResourcePips}}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
<img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' />
|
<img class='profile' src='{{source.img}}' data-action='editImage' data-edit='img' />
|
||||||
<div class='item-container'>
|
<div class='item-container'>
|
||||||
<div class="item-info">
|
<div class="item-info">
|
||||||
<h1 class='item-name'>
|
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
|
||||||
<input type='text' name='name' value='{{source.name}}' autocomplete="off" spellcheck="false"/>
|
|
||||||
</h1>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{#if @root.showStats}}
|
|
||||||
<ul class="actors-list">
|
<ul class="actors-list">
|
||||||
{{#each partyMembers as |member id|}}
|
{{#each partyMembers as |member id|}}
|
||||||
<li class="actor-resources">
|
<li class="actor-resources">
|
||||||
|
|
@ -161,26 +160,6 @@
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
{{else}}
|
|
||||||
<ul class="actors-list limited">
|
|
||||||
{{#each partyMembers as |member id|}}
|
|
||||||
<li class="actor-resources">
|
|
||||||
<div class="actor-img-frame">
|
|
||||||
<img class="actor-img" src="{{member.img}}">
|
|
||||||
</div>
|
|
||||||
<header>
|
|
||||||
<h2 class="actor-name">
|
|
||||||
<a data-action="openDocument" data-uuid="{{member.uuid}}">{{member.name}}</a>
|
|
||||||
<a class="delete-icon" data-action="deletePartyMember" data-uuid="{{member.uuid}}"><i class="fa-regular fa-times" inert></i></a>
|
|
||||||
</h2>
|
|
||||||
{{#if member.subtitle}}
|
|
||||||
<span class="subtitle">{{member.subtitle}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</header>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
{{/if}}
|
|
||||||
{{#unless document.system.partyMembers.length}}
|
{{#unless document.system.partyMembers.length}}
|
||||||
<div class="actors-dragger">
|
<div class="actors-dragger">
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.dropActorsHere"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.dropActorsHere"}}</span>
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,10 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "TYPES.Item.subclass"}}</legend>
|
<legend>{{localize "TYPES.Item.subclass"}}</legend>
|
||||||
<div class="feature-list">
|
<div class="feature-list">
|
||||||
{{#each subclasses as |subclass index|}}
|
{{#unless source.system.subclasses}}
|
||||||
|
<div class="drag-area">{{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "DAGGERHEART.GENERAL.subclasses")}}</div>
|
||||||
|
{{/unless}}
|
||||||
|
{{#each source.system.subclasses as |subclass index|}}
|
||||||
<li class='feature-item'>
|
<li class='feature-item'>
|
||||||
<div class='feature-line'>
|
<div class='feature-line'>
|
||||||
<img class='image' src='{{subclass.img}}' />
|
<img class='image' src='{{subclass.img}}' />
|
||||||
|
|
@ -41,7 +44,16 @@
|
||||||
data-item-uuid={{subclass.uuid}}
|
data-item-uuid={{subclass.uuid}}
|
||||||
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
||||||
>
|
>
|
||||||
<i class="fa-solid fa-globe" inert></i>
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class='effect-control'
|
||||||
|
data-action='removeItemFromCollection'
|
||||||
|
data-target="subclasses"
|
||||||
|
data-uuid="{{subclass.uuid}}"
|
||||||
|
data-tooltip='{{localize "CONTROLS.CommonDelete"}}'
|
||||||
|
>
|
||||||
|
<i class='fas fa-trash'></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
<div class='item-info'>
|
<div class='item-info'>
|
||||||
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
|
<h1 class='item-name'><input type='text' name='name' value='{{source.name}}' /></h1>
|
||||||
<div class='item-description'>
|
<div class='item-description'>
|
||||||
|
<h3>{{localize 'TYPES.Item.class'}}</h3>
|
||||||
<h3 class="form-fields domain-section">
|
<h3 class="form-fields domain-section">
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.Domain.plural"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.Domain.plural"}}</span>
|
||||||
<input class="domain-input" value="{{domains}}" />
|
<input class="domain-input" value="{{domains}}" />
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
<div class="item-description-outer-container">
|
<div class="item-description-outer-container">
|
||||||
{{#if spellcastTrait}}
|
|
||||||
<div class="item-description-container">
|
<div class="item-description-container">
|
||||||
<h4>{{localize "DAGGERHEART.ITEMS.Subclass.spellcastTrait"}}</h4>
|
<h4>{{localize "DAGGERHEART.ITEMS.Subclass.spellcastTrait"}}</h4>
|
||||||
<span>{{spellcastTrait}}</span>
|
<span>{{spellcastTrait}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
<div class="item-description-container">
|
<div class="item-description-container">
|
||||||
<h4>{{localize "DAGGERHEART.ITEMS.Subclass.foundationFeatures"}}</h4>
|
<h4>{{localize "DAGGERHEART.ITEMS.Subclass.foundationFeatures"}}</h4>
|
||||||
{{#each foundationFeatures as | feature |}}
|
{{#each foundationFeatures as | feature |}}
|
||||||
|
|
|
||||||
|
|
@ -3,35 +3,6 @@
|
||||||
data-tab='{{tabs.features.id}}'
|
data-tab='{{tabs.features.id}}'
|
||||||
data-group='{{tabs.features.group}}'
|
data-group='{{tabs.features.group}}'
|
||||||
>
|
>
|
||||||
<fieldset>
|
|
||||||
<legend>{{localize "TYPES.Item.class"}}</legend>
|
|
||||||
{{#if class}}
|
|
||||||
<div class="feature-list">
|
|
||||||
<li class="feature-line">
|
|
||||||
{{#if class.missing}}
|
|
||||||
<i class="fa-solid fa-link-slash hint image-icon" inert></i>
|
|
||||||
<span class="hint">{{class.name}}</span>
|
|
||||||
{{else}}
|
|
||||||
<img class="image" src="{{class.img}}" />
|
|
||||||
<span>{{class.name}}</span>
|
|
||||||
<div class='controls'>
|
|
||||||
<a
|
|
||||||
class='effect-control'
|
|
||||||
data-action='editDoc'
|
|
||||||
data-item-uuid={{class.uuid}}
|
|
||||||
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
|
||||||
>
|
|
||||||
<i class="fa-solid fa-globe" inert></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</li>
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="drag-area">{{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "TYPES.Item.class")}}</div>
|
|
||||||
{{/if}}
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<fieldset class="drop-section" data-type="foundation">
|
<fieldset class="drop-section" data-type="foundation">
|
||||||
<legend>
|
<legend>
|
||||||
{{localize "DAGGERHEART.GENERAL.Tabs.foundation"}}
|
{{localize "DAGGERHEART.GENERAL.Tabs.foundation"}}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue