mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-06-05 20:34:15 +02:00
[Fix] Improve Class-Subclass Linkage (#1846)
Some checks failed
Project CI / build (24.x) (push) Has been cancelled
Some checks failed
Project CI / build (24.x) (push) Has been cancelled
* Initial thoughts * . * Fixed linting * Continue work on updating identifier * Change to uuid approach * Localization and minor fix * Fixed CompendiumBrowser Class filter for Subclass view * Fixed the class name display in the subclass view * Improved missing class visual for subclass * Fixed character creation * Rerender class sheets when subclass link is changed * Use compendium source over actual uuid in search --------- Co-authored-by: Carlos Fernandez <cfern1990@gmail.com>
This commit is contained in:
parent
fb5e3672dc
commit
b7bc452bf5
16 changed files with 167 additions and 84 deletions
|
|
@ -2442,6 +2442,7 @@
|
||||||
"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",
|
||||||
|
|
@ -2532,6 +2533,9 @@
|
||||||
"recovery": { "label": "Recovery" },
|
"recovery": { "label": "Recovery" },
|
||||||
"type": { "label": "Type" },
|
"type": { "label": "Type" },
|
||||||
"value": { "label": "Value" }
|
"value": { "label": "Value" }
|
||||||
|
},
|
||||||
|
"identifier": {
|
||||||
|
"label": "Identifier"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Ancestry": {
|
"Ancestry": {
|
||||||
|
|
@ -3219,7 +3223,6 @@
|
||||||
"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,10 +439,13 @@ 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.uuid': { key: 'system.linkedClass.uuid', value: this.setup.class?.uuid }
|
'system.linkedClass': { key: 'system.linkedClass', value: uuid }
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (equipment.includes(type))
|
if (equipment.includes(type))
|
||||||
presets.filter = {
|
presets.filter = {
|
||||||
|
|
@ -610,7 +613,8 @@ 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')) {
|
||||||
if (this.setup.class.system.subclasses.every(subclass => subclass.uuid !== item.uuid)) {
|
const classSubclasses = await this.setup.class.system.fetchSubclasses();
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,20 +129,8 @@ 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 (item.system.linkedClass) {
|
if (['feature', 'ActiveEffect'].includes(itemType)) {
|
||||||
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') {
|
||||||
|
|
@ -200,12 +189,6 @@ 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,4 +40,36 @@ 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 = this._createFieldFilter();
|
this.fieldFilter = await 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) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createFieldFilter() {
|
async _createFieldFilter() {
|
||||||
const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters');
|
const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters');
|
||||||
filters.forEach(f => {
|
for (const f of filters) {
|
||||||
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 = f.choices(this.items);
|
f.choices = await 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,7 +370,8 @@ 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,7 +383,8 @@ export const typeConfig = {
|
||||||
{
|
{
|
||||||
key: 'system.linkedClass',
|
key: 'system.linkedClass',
|
||||||
label: 'TYPES.Item.class',
|
label: 'TYPES.Item.class',
|
||||||
format: linkedClass => linkedClass?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing'
|
format: linkedClass =>
|
||||||
|
foundry.utils.fromUuidSync(linkedClass)?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'system.spellcastingTrait',
|
key: 'system.spellcastingTrait',
|
||||||
|
|
@ -393,15 +394,18 @@ export const typeConfig = {
|
||||||
],
|
],
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
key: 'system.linkedClass.uuid',
|
key: 'system.linkedClass',
|
||||||
label: 'TYPES.Item.class',
|
label: 'TYPES.Item.class',
|
||||||
choices: items => {
|
choices: async items => {
|
||||||
const list = items
|
const list = [];
|
||||||
.filter(item => item.system.linkedClass)
|
for (const item of items.filter(item => item.system.linkedClass)) {
|
||||||
.map(item => ({
|
const linkedClass = await foundry.utils.fromUuid(item.system.linkedClass);
|
||||||
value: item.system.linkedClass.uuid,
|
list.push({
|
||||||
label: item.system.linkedClass.name
|
value: linkedClass.uuid,
|
||||||
}));
|
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.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
|
const feature = fBase.pack ? await foundry.utils.fromUuid(fBase.uuid) : fBase;
|
||||||
features.push(
|
features.push(
|
||||||
foundry.utils.mergeObject(
|
foundry.utils.mergeObject(
|
||||||
feature.toObject(),
|
feature.toObject(),
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ 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 }),
|
||||||
|
|
@ -70,6 +69,24 @@ 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 ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null })
|
linkedClass: new fields.DocumentUUIDField({ type: 'Item', nullable: true, initial: null })
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +83,8 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -861,3 +861,11 @@ 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, '');
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.feature-line {
|
.feature-line {
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -34,6 +35,14 @@
|
||||||
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;
|
||||||
|
|
@ -46,4 +55,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,8 @@
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{{localize "TYPES.Item.subclass"}}</legend>
|
<legend>{{localize "TYPES.Item.subclass"}}</legend>
|
||||||
<div class="feature-list">
|
<div class="feature-list">
|
||||||
{{#unless source.system.subclasses}}
|
{{#each subclasses as |subclass index|}}
|
||||||
<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}}' />
|
||||||
|
|
@ -44,16 +41,7 @@
|
||||||
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"></i>
|
<i class="fa-solid fa-globe" inert></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,7 +3,6 @@
|
||||||
<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,8 +1,10 @@
|
||||||
<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,6 +3,35 @@
|
||||||
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