140/141 - Class/Subclass Actions/Effects (#142)

* Added Actions and effects

* Added class hopeFeatures and classFeatures
This commit is contained in:
WBHarry 2025-06-15 13:19:48 +02:00 committed by GitHub
parent 0fbba51ad7
commit f80a849b73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 281 additions and 74 deletions

View file

@ -106,8 +106,13 @@ Hooks.once('init', () => {
Hooks.on('ready', () => { Hooks.on('ready', () => {
ui.resources = new CONFIG.ui.resources(); ui.resources = new CONFIG.ui.resources();
if(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.DisplayFear) !== 'hide') ui.resources.render({ force: true }); if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.DisplayFear) !== 'hide')
document.body.classList.toggle('theme-colorful', game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme === DualityRollColor.colorful.value); ui.resources.render({ force: true });
document.body.classList.toggle(
'theme-colorful',
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
DualityRollColor.colorful.value
);
}); });
Hooks.once('dicesoniceready', () => {}); Hooks.once('dicesoniceready', () => {});
@ -269,6 +274,8 @@ const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/sheets/character/sections/loadout.hbs', 'systems/daggerheart/templates/sheets/character/sections/loadout.hbs',
'systems/daggerheart/templates/sheets/character/parts/heritageCard.hbs', 'systems/daggerheart/templates/sheets/character/parts/heritageCard.hbs',
'systems/daggerheart/templates/sheets/character/parts/advancementCard.hbs', 'systems/daggerheart/templates/sheets/character/parts/advancementCard.hbs',
'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-features.hbs',
'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-feature.hbs',
'systems/daggerheart/templates/components/card-preview.hbs', 'systems/daggerheart/templates/components/card-preview.hbs',
'systems/daggerheart/templates/views/levelup/parts/selectable-card-preview.hbs', 'systems/daggerheart/templates/views/levelup/parts/selectable-card-preview.hbs',
'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs', 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs',

View file

@ -825,7 +825,8 @@
"Input": "Input", "Input": "Input",
"Dice": "Dice" "Dice": "Dice"
}, },
"Max": "Max" "Max": "Max",
"NewEffect": "New Effect"
}, },
"FeatureType": { "FeatureType": {
"Normal": "Normal", "Normal": "Normal",
@ -1145,6 +1146,8 @@
"Appearance": "Appearance", "Appearance": "Appearance",
"settings": "Settings" "settings": "Settings"
}, },
"HopeFeatures": "Hope Features",
"Class Features": "Class Features",
"Domains": "Domains", "Domains": "Domains",
"DamageThresholds": { "DamageThresholds": {
"Title": "Damage Thresholds", "Title": "Damage Thresholds",
@ -1254,7 +1257,9 @@
"Description": "Description", "Description": "Description",
"SubclassFeature": { "SubclassFeature": {
"Description": "Description", "Description": "Description",
"Abilities": "Abilities" "Abilities": "Abilities",
"Actions": "Actions",
"Effects": "Effects"
} }
}, },
"Weapon": { "Weapon": {

View file

@ -86,11 +86,11 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
static async updateForm(event, _, formData) { static async updateForm(event, _, formData) {
const submitData = this._prepareSubmitData(event, formData), const submitData = this._prepareSubmitData(event, formData),
data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)), data = foundry.utils.expandObject(foundry.utils.mergeObject(this.action.toObject(), submitData)),
newActions = this.action.parent.actions.map(x => x.toObject()); // Find better way newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject()); // Find better way
if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data); if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data);
const updates = await this.action.parent.parent.update({ 'system.actions': newActions }); const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions });
if (!updates) return; if (!updates) return;
this.action = updates.system.actions[this.action.index]; this.action = foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index];
this.render(); this.render();
} }

View file

@ -1,8 +1,11 @@
import { actionsTypes } from '../../../data/_module.mjs';
import { tagifyElement } from '../../../helpers/utils.mjs'; import { tagifyElement } from '../../../helpers/utils.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DaggerheartSheet from '../daggerheart-sheet.mjs'; import DaggerheartSheet from '../daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux; const { TextEditor } = foundry.applications.ux;
export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) { export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
@ -11,8 +14,9 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
actions: { actions: {
removeSubclass: this.removeSubclass, removeSubclass: this.removeSubclass,
viewSubclass: this.viewSubclass, viewSubclass: this.viewSubclass,
deleteFeature: this.deleteFeature, addFeature: this.addFeature,
editFeature: this.editFeature, editFeature: this.editFeature,
deleteFeature: this.deleteFeature,
removeItem: this.removeItem, removeItem: this.removeItem,
viewItem: this.viewItem, viewItem: this.viewItem,
removePrimaryWeapon: this.removePrimaryWeapon, removePrimaryWeapon: this.removePrimaryWeapon,
@ -151,6 +155,69 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
await this.document.update({ 'system.characterGuide.suggestedArmor': null }, { diff: false }); await this.document.update({ 'system.characterGuide.suggestedArmor': null }, { diff: false });
} }
async selectActionType() {
const content = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/views/actionType.hbs',
{ types: SYSTEM.ACTIONS.actionTypes }
),
title = 'Select Action Type',
type = 'form',
data = {};
return Dialog.prompt({
title,
label: title,
content,
type,
callback: html => {
const form = html[0].querySelector('form'),
fd = new foundry.applications.ux.FormDataExtended(form);
foundry.utils.mergeObject(data, fd.object, { inplace: true });
return data;
},
rejectClose: false
});
}
getActionPath(type) {
return type === 'hope' ? 'hopeFeatures' : 'classFeatures';
}
static async addFeature(_, target) {
const actionPath = this.getActionPath(target.dataset.type);
const actionType = await this.selectActionType();
const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack,
action = new cls(
{
_id: foundry.utils.randomID(),
systemPath: actionPath,
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
},
{
parent: this.document
}
);
await this.document.update({ [`system.${actionPath}`]: [...this.document.system[actionPath], action] });
}
static async editFeature(_, target) {
const action = this.document.system[this.getActionPath(target.dataset.type)].find(
x => x._id === target.dataset.feature
);
await new DHActionConfig(action).render(true);
}
static async deleteFeature(_, target) {
const actionPath = this.getActionPath(target.dataset.type);
await this.document.update({
[`system.${actionPath}`]: this.document.system[actionPath].filter(
action => action._id !== target.dataset.feature
)
});
}
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
@ -158,10 +225,6 @@ export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
await this.document.update({ await this.document.update({
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
}); });
} else if (item.type === 'feature') {
await this.document.update({
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
});
} else if (item.type === 'weapon') { } else if (item.type === 'weapon') {
if (event.currentTarget.classList.contains('primary-weapon-section')) { if (event.currentTarget.classList.contains('primary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary) if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary)

View file

@ -1,28 +1,24 @@
import DaggerheartSheet from '../daggerheart-sheet.mjs'; import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DhpApplicationMixin from '../daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets; const { ItemSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux; export default class SubclassSheet extends DhpApplicationMixin(ItemSheetV2) {
const { duplicate, getProperty } = foundry.utils;
export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
tag: 'form', tag: 'form',
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'subclass'], classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'subclass'],
position: { width: 600 }, position: { width: 600 },
window: { resizable: false }, window: { resizable: false },
actions: { actions: {
editAbility: this.editAbility, addFeature: this.addFeature,
deleteFeatureAbility: this.deleteFeatureAbility editFeature: this.editFeature,
deleteFeature: this.deleteFeature
}, },
form: { form: {
handler: this.updateForm, handler: this.updateForm,
submitOnChange: true, submitOnChange: true,
closeOnSubmit: false closeOnSubmit: false
}, }
dragDrop: [
{ dragSelector: null, dropSelector: '.foundation-tab' },
{ dragSelector: null, dropSelector: '.specialization-tab' },
{ dragSelector: null, dropSelector: '.mastery-tab' }
]
}; };
static PARTS = { static PARTS = {
@ -80,41 +76,99 @@ export default class SubclassSheet extends DaggerheartSheet(ItemSheetV2) {
this.render(); this.render();
} }
static async editAbility(_, button) { static addFeature(_, target) {
const feature = await fromUuid(button.dataset.ability); if (target.dataset.type === 'action') this.addAction(target.dataset.level);
feature.sheet.render(true); else this.addEffect(target.dataset.level);
} }
static async deleteFeatureAbility(event, button) { static async editFeature(_, target) {
event.preventDefault(); if (target.dataset.type === 'action') this.editAction(target.dataset.level, target.dataset.feature);
event.stopPropagation(); else this.editEffect(target.dataset.feature);
const feature = button.dataset.feature;
const newAbilities = this.document.system[`${feature}Feature`].abilities.filter(
x => x.uuid !== button.dataset.ability
);
const path = `system.${feature}Feature.abilities`;
await this.document.update({ [path]: newAbilities });
} }
async _onDrop(event) { static async deleteFeature(_, target) {
event.preventDefault(); if (target.dataset.type === 'action') this.removeAction(target.dataset.level, target.dataset.feature);
const data = TextEditor.getDragEventData(event); else this.removeEffect(target.dataset.level, target.dataset.feature);
const item = await fromUuid(data.uuid); }
if (!(item.type === 'feature' && item.system.type === SYSTEM.ITEM.featureTypes.subclass.id)) return;
let featureField; async #selectActionType() {
if (event.currentTarget.classList.contains('foundation-tab')) featureField = 'foundation'; const content = await foundry.applications.handlebars.renderTemplate(
else if (event.currentTarget.classList.contains('specialization-tab')) featureField = 'specialization'; 'systems/daggerheart/templates/views/actionType.hbs',
else if (event.currentTarget.classList.contains('mastery-tab')) featureField = 'mastery'; { types: SYSTEM.ACTIONS.actionTypes }
else return; ),
title = 'Select Action Type',
type = 'form',
data = {};
return Dialog.prompt({
title,
label: title,
content,
type,
callback: html => {
const form = html[0].querySelector('form'),
fd = new foundry.applications.ux.FormDataExtended(form);
foundry.utils.mergeObject(data, fd.object, { inplace: true });
return data;
},
rejectClose: false
});
}
const path = `system.${featureField}Feature.abilities`; async addAction(level) {
const abilities = duplicate(getProperty(this.document, path)) || []; const actionType = await this.#selectActionType();
const featureData = { name: item.name, img: item.img, uuid: item.uuid }; const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack,
abilities.push(featureData); action = new cls(
{
_id: foundry.utils.randomID(),
systemPath: `${level}.actions`,
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
},
{
parent: this.document
}
);
await this.document.update({ [`system.${level}.actions`]: [...this.document.system[level].actions, action] });
await new DHActionConfig(
this.document.system[level].actions[this.document.system[level].actions.length - 1]
).render(true);
}
await this.document.update({ [path]: abilities }); async addEffect(level) {
const embeddedItems = await this.document.createEmbeddedDocuments('ActiveEffect', [
{ name: game.i18n.localize('DAGGERHEART.Feature.NewEffect') }
]);
await this.document.update({
[`system.${level}.effects`]: [
...this.document.system[level].effects.map(x => x.uuid),
embeddedItems[0].uuid
]
});
}
async editAction(level, id) {
const action = this.document.system[level].actions.find(x => x._id === id);
await new DHActionConfig(action).render(true);
}
async editEffect(id) {
const effect = this.document.effects.get(id);
effect.sheet.render(true);
}
async removeAction(level, id) {
await this.document.update({
[`system.${level}.actions`]: this.document.system[level].actions.filter(action => action._id !== id)
});
}
async removeEffect(level, id) {
await this.document.effects.get(id).delete();
await this.document.update({
[`system.${level}.effects`]: this.document.system[level].effects
.filter(x => x && x.id !== id)
.map(effect => effect.uuid)
});
} }
} }

View file

@ -55,6 +55,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
static defineSchema() { static defineSchema() {
return { return {
_id: new fields.DocumentIdField(), _id: new fields.DocumentIdField(),
systemPath: new fields.StringField({ required: true, initial: 'actions' }),
type: new fields.StringField({ initial: undefined, readonly: true, required: true }), type: new fields.StringField({ initial: undefined, readonly: true, required: true }),
name: new fields.StringField({ initial: undefined }), name: new fields.StringField({ initial: undefined }),
img: new fields.FilePathField({ initial: undefined, categories: ['IMAGE'], base64: false }), img: new fields.FilePathField({ initial: undefined, categories: ['IMAGE'], base64: false }),
@ -93,7 +94,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
prepareData() {} prepareData() {}
get index() { get index() {
return this.parent.actions.indexOf(this); return foundry.utils.getProperty(this.parent, this.systemPath).indexOf(this);
} }
get item() { get item() {

View file

@ -1,5 +1,6 @@
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ActionField from '../fields/actionField.mjs';
export default class DHClass extends BaseDataItem { export default class DHClass extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
@ -19,7 +20,8 @@ export default class DHClass extends BaseDataItem {
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }), domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
classItems: new fields.ArrayField(new ForeignDocumentUUIDField({ type: 'Item' })), classItems: new fields.ArrayField(new ForeignDocumentUUIDField({ type: 'Item' })),
evasion: new fields.NumberField({ initial: 0, integer: true }), evasion: new fields.NumberField({ initial: 0, integer: true }),
features: new fields.ArrayField(new ForeignDocumentUUIDField({ type: 'Item' })), hopeFeatures: new foundry.data.fields.ArrayField(new ActionField()),
classFeatures: new foundry.data.fields.ArrayField(new ActionField()),
subclasses: new fields.ArrayField( subclasses: new fields.ArrayField(
new ForeignDocumentUUIDField({ type: 'Item', required: false, nullable: true, initial: undefined }) new ForeignDocumentUUIDField({ type: 'Item', required: false, nullable: true, initial: undefined })
), ),
@ -51,6 +53,10 @@ export default class DHClass extends BaseDataItem {
}; };
} }
get hopeFeature() {
return this.hopeFeatures.length > 0 ? this.hopeFeatures[0] : null;
}
async _preCreate(data, options, user) { async _preCreate(data, options, user) {
const allowed = await super._preCreate(data, options, user); const allowed = await super._preCreate(data, options, user);
if (allowed === false) return; if (allowed === false) return;

View file

@ -1,6 +1,15 @@
import ActionField from '../fields/actionField.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
const featureSchema = () => {
return new foundry.data.fields.SchemaField({
name: new foundry.data.fields.StringField({ required: true }),
effects: new foundry.data.fields.ArrayField(new ForeignDocumentUUIDField({ type: 'ActiveEffect' })),
actions: new foundry.data.fields.ArrayField(new ActionField())
});
};
export default class DHSubclass extends BaseDataItem { export default class DHSubclass extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
static get metadata() { static get metadata() {
@ -22,9 +31,9 @@ export default class DHSubclass extends BaseDataItem {
nullable: true, nullable: true,
initial: null initial: null
}), }),
foundationFeature: new ForeignDocumentUUIDField({ type: 'Item' }), foundationFeature: featureSchema(),
specializationFeature: new ForeignDocumentUUIDField({ type: 'Item' }), specializationFeature: featureSchema(),
masteryFeature: new ForeignDocumentUUIDField({ type: 'Item' }), masteryFeature: featureSchema(),
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 })
}; };

View file

@ -3579,7 +3579,6 @@ div.daggerheart.views.multiclass {
} }
.sheet.daggerheart.dh-style.item .tab.features { .sheet.daggerheart.dh-style.item .tab.features {
padding: 0 10px; padding: 0 10px;
max-height: 265px;
overflow-y: auto; overflow-y: auto;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: light-dark(#18162e, #f3c267) transparent; scrollbar-color: light-dark(#18162e, #f3c267) transparent;

View file

@ -4,7 +4,6 @@
.sheet.daggerheart.dh-style.item { .sheet.daggerheart.dh-style.item {
.tab.features { .tab.features {
padding: 0 10px; padding: 0 10px;
max-height: 265px;
overflow-y: auto; overflow-y: auto;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: light-dark(@dark-blue, @golden) transparent; scrollbar-color: light-dark(@dark-blue, @golden) transparent;

View file

@ -9,7 +9,8 @@
<a <a
class='effect-control' class='effect-control'
data-action='editFeature' data-action='editFeature'
data-feature='{{feature.uuid}}' data-feature='{{feature._id}}'
data-type='{{type}}'
data-tooltip='{{localize "DAGGERHEART.Tooltip.openItemWorld"}}' data-tooltip='{{localize "DAGGERHEART.Tooltip.openItemWorld"}}'
> >
<i class="fa-solid fa-globe"></i> <i class="fa-solid fa-globe"></i>
@ -17,7 +18,8 @@
<a <a
class='effect-control' class='effect-control'
data-action='deleteFeature' data-action='deleteFeature'
data-feature='{{feature.uuid}}' data-feature='{{feature._id}}'
data-type='{{type}}'
data-tooltip='{{localize "DAGGERHEART.Tooltip.delete"}}' data-tooltip='{{localize "DAGGERHEART.Tooltip.delete"}}'
> >
<i class='fas fa-trash'></i> <i class='fas fa-trash'></i>

View file

@ -3,15 +3,25 @@
data-tab='{{tabs.features.id}}' data-tab='{{tabs.features.id}}'
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<div class="two-columns even">
<fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Class.HopeFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="hope" data-action="addFeature"></i></a></legend>
<div class="feature-list">
{{#each source.system.hopeFeatures as |feature index|}}
{{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' type='hope' feature=feature}}
{{/each}}
</div>
</fieldset>
<fieldset> <fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Feature.Tabs.Features"}}</legend> <legend>{{localize "DAGGERHEART.Sheets.Class.ClassFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="class" data-action="addFeature"></i></a></legend>
<div class="feature-list"> <div class="feature-list">
{{#each source.system.features as |feature index|}} {{#each source.system.classFeatures as |feature index|}}
{{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' feature=feature}} {{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' type='class' feature=feature}}
{{/each}} {{/each}}
</div> </div>
</fieldset> </fieldset>
</div>
<fieldset> <fieldset>
<legend>{{localize "TYPES.Item.subclass"}}</legend> <legend>{{localize "TYPES.Item.subclass"}}</legend>

View file

@ -5,16 +5,16 @@
> >
<fieldset> <fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Foundation"}}</legend> <legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Foundation"}}</legend>
{{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' feature=source.system.foundationFeature}} {{> 'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-features.hbs' level='foundationFeature' feature=source.system.foundationFeature}}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Specialization"}}</legend> <legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Specialization"}}</legend>
{{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' feature=source.system.specializationFeature}} {{> 'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-features.hbs' level='specializationFeature' feature=source.system.specializationFeature}}
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Mastery"}}</legend> <legend>{{localize "DAGGERHEART.Sheets.Subclass.Tabs.Mastery"}}</legend>
{{> 'systems/daggerheart/templates/sheets/global/partials/feature-section-item.hbs' feature=source.system.masteryFeature}} {{> 'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-features.hbs' level='masteryFeature' feature=source.system.masteryFeature}}
</fieldset> </fieldset>
</section> </section>

View file

@ -0,0 +1,30 @@
<li class='feature-item'>
<div class='feature-line'>
<img class='image' src='{{feature.img}}' />
<h4>{{feature.name}}</h4>
{{#unless hideContrals}}
<div class='controls'>
<a
class='effect-control'
data-action='editFeature'
data-type="{{type}}"
data-level="{{level}}"
data-feature='{{id}}'
data-tooltip='{{localize "DAGGERHEART.Tooltip.openItemWorld"}}'
>
<i class="fa-solid fa-globe"></i>
</a>
<a
class='effect-control'
data-action='deleteFeature'
data-type="{{type}}"
data-level="{{level}}"
data-feature='{{id}}'
data-tooltip='{{localize "DAGGERHEART.Tooltip.delete"}}'
>
<i class='fas fa-trash'></i>
</a>
</div>
{{/unless}}
</div>
</li>

View file

@ -0,0 +1,22 @@
<div class="two-columns even">
<fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Subclass.SubclassFeature.Actions"}} <a><i class="fa-solid fa-plus icon-button" data-level="{{level}}" data-type="action" data-action="addFeature"></i></a></legend>
<div class="feature-list">
{{#each feature.actions}}
{{> 'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-feature.hbs' level=../level type="action" id=this._id feature=this}}
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "DAGGERHEART.Sheets.Subclass.SubclassFeature.Effects"}} <a><i class="fa-solid fa-plus icon-button" data-level="{{level}}" data-type="effect" data-action="addFeature"></i></a></legend>
<div class="feature-list">
{{#each feature.effects}}
{{> 'systems/daggerheart/templates/sheets/items/subclass/parts/subclass-feature.hbs' level=../level type="effect" id=this.id feature=this}}
{{/each}}
</div>
</fieldset>
</div>