[Feature] Manual Character Editing (#490)

* Initial

* Added Character-Settings

* Finalized Character-Settings

* Hide CharacterSetup if any part is done manually

* Fixed class/subclass drag-drop

* Fixed relinking of Features from items created on Character

* Adding features on CharacterItems now adds them on the Character and relinks

* Made suggested items inactive in the Class sheet if rendered from inside a Character

* Added hope to CharacterSetting

* add style to textarea element, add spellcasting and domain class into char sheet and move rest buttons to another place

* Fixed characterCreation experience description

---------

Co-authored-by: moliloo <dev.murilobrito@gmail.com>
This commit is contained in:
WBHarry 2025-08-01 17:16:35 +02:00 committed by GitHub
parent 263dfa69ae
commit e1d8f8784a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 1205 additions and 386 deletions

View file

@ -162,11 +162,25 @@
},
"faith": "Faith",
"levelUp": "You can level up",
"maxEvasionBonus": "Max Evasion Increase",
"maxHPBonus": "Max HP Increase",
"pronouns": "Pronouns",
"story": {
"backgroundTitle": "Background",
"characteristics": "Characteristics",
"connectionsTitle": "Connections"
},
"experienceDataRemoveConfirmation": {
"title": "Remove Experience Data",
"text": "The experience you are about to remove has levelup data linked to it (assumably because you did levelups with the 'levelupAuto' automation setting on). Removing it will remove this automation data aswell. Do you want to proceed?"
},
"manualMulticlass": {
"title": "Multiclass",
"text": "Do you want to add this class as your multiclass?"
},
"manualMulticlassSubclass": {
"title": "Multiclass Subclass",
"text": "Do you want to add this subclass as your multiclass subclass?"
}
},
"Companion": {
@ -460,6 +474,11 @@
},
"title": "{actor} Level Up"
},
"MulticlassChoice": {
"title": "Multiclassing - {actor}",
"explanation": "You are adding {class} as your multiclass",
"selectDomainPrompt": "Select your new domain"
},
"OwnershipSelection": {
"title": "Ownership Selection - {name}",
"default": "Default Ownership"
@ -1866,6 +1885,7 @@
"levelUp": "Level Up",
"loadout": "Loadout",
"max": "Max",
"maxWithThing": "Max {thing}",
"multiclass": "Multiclass",
"newCategory": "New Category",
"none": "None",
@ -2022,6 +2042,10 @@
"gm": { "label": "GM" },
"players": { "label": "Players" }
},
"levelupAuto": {
"label": "Levelup Automation",
"hint": "When you've made your choices and finish levelup, the numerical changes are automatically applied to your character."
},
"actionPoints": {
"label": "Action Points",
"hint": "Automatically give and take Action Points as combatants take their turns."
@ -2205,7 +2229,9 @@
"tooHighLevel": "You cannot raise the character level past the maximum",
"tooLowLevel": "You cannot lower the character level below starting level",
"subclassNotInClass": "This subclass does not belong to your selected class.",
"subclassNotInMulticlass": "This subclass does not belong to your selected multiclass.",
"missingClass": "You don't have a class selected yet.",
"missingMulticlass": "Missing multiclass",
"wrongDomain": "The card isn't from one of your class domains.",
"cardTooHighLevel": "The card is too high level!",
"duplicateCard": "You cannot select the same card more than once.",
@ -2235,7 +2261,9 @@
"beastformToManyFeatures": "You cannot select any more features.",
"beastformEquipWeapon": "You cannot use weapons while in a Beastform.",
"loadoutMaxReached": "You already have {max} cards in your loadout. Move atleast one to your vault before adding a new one.",
"insufficientResources": "You have insufficient resources"
"insufficientResources": "You have insufficient resources",
"multiclassAlreadyPresent": "You already have a class and multiclass",
"subclassesAlreadyPresent": "You already have a class and multiclass subclass"
},
"Tooltip": {
"disableEffect": "Disable Effect",
@ -2243,6 +2271,8 @@
"openItemWorld": "Open Item World",
"openActorWorld": "Open Actor World",
"sendToChat": "Send to Chat",
"maxEvasionClassBound": "Your Evasion base is set on your class. This is the increase ontop of that.",
"maxHPClassBound": "Your max HP base is set on your class. This is the increase ontop of that.",
"moreOptions": "More Options",
"equip": "Equip",
"unequip": "Unequip",
@ -2252,7 +2282,8 @@
"rangeAndTarget": "Range & Target",
"dragApplyEffect": "Drag effect to apply it to an actor",
"appliedEvenIfSuccessful": "Applied even if save succeeded",
"diceIsRerolled": "The dice has been rerolled (x{times})"
"diceIsRerolled": "The dice has been rerolled (x{times})",
"openSheetSettings": "Open Settings"
}
}
}

View file

@ -5,6 +5,7 @@ export { default as DamageReductionDialog } from './damageReductionDialog.mjs';
export { default as DamageSelectionDialog } from './damageSelectionDialog.mjs';
export { default as DeathMove } from './deathMove.mjs';
export { default as Downtime } from './downtime.mjs';
export { default as MulticlassChoiceDialog } from './multiclassChoiceDialog.mjs';
export { default as OwnershipSelection } from './ownershipSelection.mjs';
export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';

View file

@ -0,0 +1,73 @@
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class MulticlassChoiceDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(actor, multiclass, options) {
super(options);
this.actor = actor;
this.multiclass = multiclass;
this.selectedDomain = null;
}
get title() {
return game.i18n.format('DAGGERHEART.APPLICATIONS.MulticlassChoice.title', { actor: this.actor.name });
}
static DEFAULT_OPTIONS = {
classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'multiclass-choice'],
position: { width: 'auto', height: 'auto' },
window: { icon: 'fa-solid fa-person-rays' },
actions: {
save: MulticlassChoiceDialog.#save,
selectDomain: MulticlassChoiceDialog.#selectDomain
}
};
static PARTS = {
application: {
id: 'multiclass-choice',
template: 'systems/daggerheart/templates/dialogs/multiclassChoice.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.multiclass = this.multiclass;
context.domainChoices = this.multiclass.domains.map(value => {
const domain = CONFIG.DH.DOMAIN.domains[value];
return {
value: value,
label: game.i18n.localize(domain.label),
description: game.i18n.localize(domain.description),
src: domain.src,
selected: value === this.selectedDomain,
disabled: this.actor.system.domains.includes(value)
};
});
context.multiclassDisabled = !this.selectedDomain;
return context;
}
/** @override */
_onClose(options = {}) {
if (!options.submitted) this.move = null;
}
static async configure(actor, multiclass, options = {}) {
return new Promise(resolve => {
const app = new this(actor, multiclass, options);
app.addEventListener('close', () => resolve(app.selectedDomain), { once: true });
app.render({ force: true });
});
}
static #save() {
this.close({ submitted: true });
}
static #selectDomain(_event, button) {
this.selectedDomain = this.selectedDomain === button.dataset.domain ? null : button.dataset.domain;
this.render();
}
}

View file

@ -46,7 +46,8 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
tabs: { template: 'systems/daggerheart/templates/levelup/tabs/tab-navigation.hbs' },
advancements: { template: 'systems/daggerheart/templates/levelup/tabs/advancements.hbs' },
selections: { template: 'systems/daggerheart/templates/levelup/tabs/selections.hbs' },
summary: { template: 'systems/daggerheart/templates/levelup/tabs/summary.hbs' }
summary: { template: 'systems/daggerheart/templates/levelup/tabs/summary.hbs' },
footer: { template: 'systems/daggerheart/templates/levelup/tabs/footer.hbs' }
};
static TABS = {
@ -95,6 +96,7 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
const context = await super._prepareContext(_options);
context.levelup = this.levelup;
context.tabs = this._getTabs(this.constructor.TABS);
context.levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
return context;
}

View file

@ -1,4 +1,5 @@
export { default as ActionConfig } from './action-config.mjs';
export { default as CharacterSettings } from './character-settings.mjs';
export { default as AdversarySettings } from './adversary-settings.mjs';
export { default as CompanionSettings } from './companion-settings.mjs';
export { default as DowntimeConfig } from './downtimeConfig.mjs';

View file

@ -0,0 +1,143 @@
import DHBaseActorSettings from '../sheets/api/actor-setting.mjs';
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
export default class DHCharacterSettings extends DHBaseActorSettings {
/**@inheritdoc */
static DEFAULT_OPTIONS = {
classes: ['character-settings'],
position: { width: 455, height: 'auto' },
actions: {
addExperience: DHCharacterSettings.#addExperience,
removeExperience: DHCharacterSettings.#removeExperience
},
dragDrop: [
{ dragSelector: null, dropSelector: '.tab.features' },
{ dragSelector: '.feature-item', dropSelector: null }
]
};
/**@override */
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets-settings/character-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets-settings/character-settings/details.hbs'
},
experiences: {
id: 'experiences',
template: 'systems/daggerheart/templates/sheets-settings/character-settings/experiences.hbs'
}
};
/** @override */
static TABS = {
primary: {
tabs: [{ id: 'details' }, { id: 'experiences' }],
initial: 'details',
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
}
};
/**@inheritdoc */
async _prepareContext(options) {
const context = await super._prepareContext(options);
context.levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
return context;
}
/* -------------------------------------------- */
/**
* Adds a new experience entry to the actor.
* @type {ApplicationClickAction}
*/
static async #addExperience() {
const newExperience = {
name: 'Experience',
modifier: 0
};
await this.actor.update({ [`system.experiences.${foundry.utils.randomID()}`]: newExperience });
}
/**
* Removes an experience entry from the actor.
* @type {ApplicationClickAction}
*/
static async #removeExperience(_, target) {
const experience = this.actor.system.experiences[target.dataset.experience];
const updates = {};
const relinkAchievementData = [];
const relinkSelectionData = [];
Object.keys(this.actor.system.levelData.levelups).forEach(key => {
const level = this.actor.system.levelData.levelups[key];
const achievementIncludesExp = level.achievements.experiences[target.dataset.experience];
if (achievementIncludesExp)
relinkAchievementData.push({ levelKey: key, experience: target.dataset.experience });
const selectionIndex = level.selections.findIndex(
x => x.optionKey === 'experience' && x.data[0] === target.dataset.experience
);
if (selectionIndex !== -1)
relinkSelectionData.push({ levelKey: key, selectionIndex, experience: target.dataset.experience });
});
if (relinkAchievementData.length > 0 || relinkSelectionData.length > 0) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.localize('DAGGERHEART.ACTORS.Character.experienceDataRemoveConfirmation.title')
},
content: game.i18n.localize('DAGGERHEART.ACTORS.Character.experienceDataRemoveConfirmation.text')
});
if (!confirmed) return;
}
if (relinkAchievementData.length > 0) {
relinkAchievementData.forEach(data => {
updates[`system.levelData.levelups.${data.levelKey}.achievements.experiences.-=${data.experience}`] =
null;
});
} else if (relinkSelectionData.length > 0) {
relinkSelectionData.forEach(data => {
updates[`system.levelData.levelups.${data.levelKey}.selections`] = this.actor.system.levelData.levelups[
data.levelKey
].selections.reduce((acc, selection, index) => {
if (
index === data.selectionIndex &&
selection.optionKey === 'experience' &&
selection.data.includes(data.experience)
) {
acc.push({ ...selection, data: selection.data.filter(x => x !== data.experience) });
} else {
acc.push(selection);
}
return acc;
}, []);
});
} else {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
type: game.i18n.localize(`DAGGERHEART.GENERAL.Experience.single`),
name: experience.name
})
},
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: experience.name })
});
if (!confirmed) return;
}
await this.actor.update({
...updates,
[`system.experiences.-=${target.dataset.experience}`]: null
});
}
}

View file

@ -10,6 +10,8 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
classes: ['companion-settings'],
position: { width: 455, height: 'auto' },
actions: {
addExperience: DHCompanionSettings.#addExperience,
removeExperience: DHCompanionSettings.#removeExperience,
levelUp: DHCompanionSettings.#levelUp
}
};
@ -88,6 +90,38 @@ export default class DHCompanionSettings extends DHBaseActorSettings {
if (!value) await this.actor.updateLevel(1);
}
/**
* Adds a new experience entry to the actor.
* @type {ApplicationClickAction}
*/
static async #addExperience() {
const newExperience = {
name: 'Experience',
modifier: 0
};
await this.actor.update({ [`system.experiences.${foundry.utils.randomID()}`]: newExperience });
}
/**
* Removes an experience entry from the actor.
* @type {ApplicationClickAction}
*/
static async #removeExperience(_, target) {
const experience = this.actor.system.experiences[target.dataset.experience];
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
type: game.i18n.localize(`DAGGERHEART.GENERAL.Experience.single`),
name: experience.name
})
},
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: experience.name })
});
if (!confirmed) return;
await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null });
}
/**
* Opens the companion level-up dialog for the associated actor.
* @type {ApplicationClickAction}

View file

@ -716,10 +716,14 @@ export default class CharacterSheet extends DHBaseActorSheet {
});
}
/**
* Open the downtime application.
* @type {ApplicationClickAction}
*/
static useDowntime(_, button) {
new game.system.api.applications.dialogs.Downtime(this.document, button.dataset.type === 'shortRest').render(
true
);
new game.system.api.applications.dialogs.Downtime(this.document, button.dataset.type === 'shortRest').render({
force: true
});
}
async _onDragStart(event) {

View file

@ -417,17 +417,29 @@ export default function DHApplicationMixin(Base) {
const { documentClass, type, inVault, disabled } = target.dataset;
const parentIsItem = this.document.documentName === 'Item';
const parent =
parentIsItem && documentClass === 'Item'
? type === 'action'
? this.document.system
: null
: this.document;
this.document.parent?.type === 'character'
? this.document.parent
: parentIsItem && documentClass === 'Item'
? type === 'action'
? this.document.system
: null
: this.document;
let systemData = {};
if (parent?.type === 'character' && type === 'feature') {
systemData = {
originItemType: this.document.type,
originId: this.document.id,
identifier: this.document.system.isMulticlass ? 'multiclass' : null
};
}
const cls =
type === 'action' ? game.system.api.models.actions.actionsTypes.base : getDocumentClass(documentClass);
const data = {
name: cls.defaultName({ type, parent }),
type
type,
system: systemData
};
if (inVault) data['system.inVault'] = true;
if (disabled) data.disabled = true;

View file

@ -150,10 +150,24 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
static async #addFeature(_, target) {
const { type } = target.dataset;
const cls = foundry.documents.Item.implementation;
const item = await cls.create({
type: 'feature',
name: cls.defaultName({ type: 'feature' })
});
let systemData = {};
if (this.document.parent?.type === 'character') {
systemData = {
originItemType: this.document.type,
originId: this.document.id,
identifier: this.document.system.isMulticlass ? 'multiclass' : null
};
}
const item = await cls.create(
{
type: 'feature',
name: cls.defaultName({ type: 'feature' }),
system: systemData
},
{ parent: this.document.parent?.type === 'character' ? this.document.parent : undefined }
);
await this.document.update({
'system.features': [...this.document.system.features, { type, item }].map(x => ({
...x,

View file

@ -113,45 +113,47 @@ export default class ClassSheet extends DHBaseItemSheet {
});
} else if (item.type === 'feature') {
super._onDrop(event);
} else if (item.type === 'weapon') {
if (target.classList.contains('primary-weapon-section')) {
if (!item.system.secondary)
} else if (this.document.parent?.type !== 'character') {
if (item.type === 'weapon') {
if (target.classList.contains('primary-weapon-section')) {
if (!item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedPrimaryWeapon': item.uuid
});
} else if (target.classList.contains('secondary-weapon-section')) {
if (item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedSecondaryWeapon': item.uuid
});
}
} else if (item.type === 'armor') {
if (target.classList.contains('armor-section')) {
await this.document.update({
'system.characterGuide.suggestedPrimaryWeapon': item.uuid
});
} else if (target.classList.contains('secondary-weapon-section')) {
if (item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedSecondaryWeapon': item.uuid
});
}
} else if (item.type === 'armor') {
if (target.classList.contains('armor-section')) {
await this.document.update({
'system.characterGuide.suggestedArmor': item.uuid
});
}
} else if (target.classList.contains('choice-a-section')) {
if (item.type === 'loot' || item.type === 'consumable') {
const filteredChoiceA = this.document.system.inventory.choiceA;
if (filteredChoiceA.length < 2)
await this.document.update({
'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid]
});
}
} else if (item.type === 'loot') {
if (target.classList.contains('take-section')) {
const filteredTake = this.document.system.inventory.take.filter(x => x);
if (filteredTake.length < 3)
await this.document.update({
'system.inventory.take': [...filteredTake.map(x => x.uuid), item.uuid]
});
} else if (target.classList.contains('choice-b-section')) {
const filteredChoiceB = this.document.system.inventory.choiceB.filter(x => x);
if (filteredChoiceB.length < 2)
await this.document.update({
'system.inventory.choiceB': [...filteredChoiceB.map(x => x.uuid), item.uuid]
'system.characterGuide.suggestedArmor': item.uuid
});
}
} else if (target.classList.contains('choice-a-section')) {
if (item.type === 'loot' || item.type === 'consumable') {
const filteredChoiceA = this.document.system.inventory.choiceA;
if (filteredChoiceA.length < 2)
await this.document.update({
'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid]
});
}
} else if (item.type === 'loot') {
if (target.classList.contains('take-section')) {
const filteredTake = this.document.system.inventory.take.filter(x => x);
if (filteredTake.length < 3)
await this.document.update({
'system.inventory.take': [...filteredTake.map(x => x.uuid), item.uuid]
});
} else if (target.classList.contains('choice-b-section')) {
const filteredChoiceB = this.document.system.inventory.choiceB.filter(x => x);
if (filteredChoiceB.length < 2)
await this.document.update({
'system.inventory.choiceB': [...filteredChoiceB.map(x => x.uuid), item.uuid]
});
}
}
}
}

View file

@ -87,7 +87,8 @@ export default class DhpAdversary extends BaseDataActor {
experiences: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField(),
value: new fields.NumberField({ required: true, integer: true, initial: 1 })
value: new fields.NumberField({ required: true, integer: true, initial: 1 }),
description: new fields.StringField()
})
),
bonuses: new fields.SchemaField({

View file

@ -4,6 +4,7 @@ import DhLevelData from '../levelData.mjs';
import BaseDataActor from './base.mjs';
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
import { ActionField } from '../fields/actionField.mjs';
import DHCharacterSettings from '../../applications/sheets-configs/character-settings.mjs';
export default class DhCharacter extends BaseDataActor {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
@ -12,6 +13,7 @@ export default class DhCharacter extends BaseDataActor {
return foundry.utils.mergeObject(super.metadata, {
label: 'TYPES.Actor.character',
type: 'character',
settingSheet: DHCharacterSettings,
isNPC: false
});
}
@ -22,7 +24,12 @@ export default class DhCharacter extends BaseDataActor {
return {
...super.defineSchema(),
resources: new fields.SchemaField({
hitPoints: resourceField(0, 'DAGGERHEART.GENERAL.HitPoints.plural', true),
hitPoints: resourceField(
0,
'DAGGERHEART.GENERAL.HitPoints.plural',
true,
'DAGGERHEART.ACTORS.Character.maxHPBonus'
),
stress: resourceField(6, 'DAGGERHEART.GENERAL.stress', true),
hope: resourceField(6, 'DAGGERHEART.GENERAL.hope')
}),
@ -56,7 +63,8 @@ export default class DhCharacter extends BaseDataActor {
experiences: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField(),
value: new fields.NumberField({ integer: true, initial: 0 })
value: new fields.NumberField({ integer: true, initial: 0 }),
description: new fields.StringField()
})
),
gold: new fields.SchemaField({
@ -312,7 +320,7 @@ export default class DhCharacter extends BaseDataActor {
}
get needsCharacterSetup() {
return !this.class.value || !this.class.subclass;
return !(this.class.value || this.class.subclass || this.ancestry || this.community);
}
get spellcastModifier() {
@ -399,11 +407,16 @@ export default class DhCharacter extends BaseDataActor {
} else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) {
if (this.class.subclass) {
const subclassState = this.class.subclass.system.featureState;
const subType = item.system.subType;
const subclass =
item.system.identifier === 'multiclass' ? this.multiclass.subclass : this.class.subclass;
const featureType = subclass
? (subclass.system.features.find(x => x.item?.uuid === item.uuid)?.type ?? null)
: null;
if (
subType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
(subType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
(subType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
featureType === CONFIG.DH.ITEM.featureSubTypes.foundation ||
(featureType === CONFIG.DH.ITEM.featureSubTypes.specialization && subclassState >= 2) ||
(featureType === CONFIG.DH.ITEM.featureSubTypes.mastery && subclassState >= 3)
) {
subclassFeatures.push(item);
}
@ -502,7 +515,7 @@ export default class DhCharacter extends BaseDataActor {
}
prepareBaseData() {
this.evasion = this.class.value?.system?.evasion ?? 0;
this.evasion += this.class.value?.system?.evasion ?? 0;
const currentLevel = this.levelData.level.current;
const currentTier =
@ -511,37 +524,39 @@ export default class DhCharacter extends BaseDataActor {
: Object.values(game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers).find(
tier => currentLevel >= tier.levels.start && currentLevel <= tier.levels.end
).tier;
for (let levelKey in this.levelData.levelups) {
const level = this.levelData.levelups[levelKey];
if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto) {
for (let levelKey in this.levelData.levelups) {
const level = this.levelData.levelups[levelKey];
this.proficiency += level.achievements.proficiency;
this.proficiency += level.achievements.proficiency;
for (let selection of level.selections) {
switch (selection.type) {
case 'trait':
selection.data.forEach(data => {
this.traits[data].value += 1;
this.traits[data].tierMarked = selection.tier === currentTier;
});
break;
case 'hitPoint':
this.resources.hitPoints.max += selection.value;
break;
case 'stress':
this.resources.stress.max += selection.value;
break;
case 'evasion':
this.evasion += selection.value;
break;
case 'proficiency':
this.proficiency += selection.value;
break;
case 'experience':
Object.keys(this.experiences).forEach(key => {
const experience = this.experiences[key];
experience.value += selection.value;
});
break;
for (let selection of level.selections) {
switch (selection.type) {
case 'trait':
selection.data.forEach(data => {
this.traits[data].value += 1;
this.traits[data].tierMarked = selection.tier === currentTier;
});
break;
case 'hitPoint':
this.resources.hitPoints.max += selection.value;
break;
case 'stress':
this.resources.stress.max += selection.value;
break;
case 'evasion':
this.evasion += selection.value;
break;
case 'proficiency':
this.proficiency += selection.value;
break;
case 'experience':
selection.data.forEach(id => {
const experience = this.experiences[id];
if (experience) experience.value += selection.value;
});
break;
}
}
}
}

View file

@ -6,10 +6,15 @@ const attributeField = label =>
tierMarked: new fields.BooleanField({ initial: false })
});
const resourceField = (max = 0, label, reverse = false) =>
const resourceField = (max = 0, label, reverse = false, maxLabel) =>
new fields.SchemaField({
value: new fields.NumberField({ initial: 0, min: 0, integer: true, label }),
max: new fields.NumberField({ initial: max, integer: true }),
max: new fields.NumberField({
initial: max,
integer: true,
label:
maxLabel ?? game.i18n.format('DAGGERHEART.GENERAL.maxWithThing', { thing: game.i18n.localize(label) })
}),
isReversed: new fields.BooleanField({ initial: reverse })
});

View file

@ -125,6 +125,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
}
if (this.actor && this.actor.type === 'character' && this.features) {
const featureUpdates = {};
for (let f of this.features) {
const fBase = f.item ?? f;
const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid);
@ -134,14 +135,26 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
system: {
originItemType: this.parent.type,
originId: data._id,
identifier: feature.identifier,
subType: feature.item ? feature.type : undefined
identifier: this.isMulticlass ? 'multiclass' : null
}
},
{ inplace: false }
);
await this.actor.createEmbeddedDocuments('Item', [createData]);
const [doc] = await this.actor.createEmbeddedDocuments('Item', [createData]);
if (!featureUpdates.features)
featureUpdates.features = this.features.map(x => (x.item ? { ...x, item: x.item.uuid } : x.uuid));
if (f.item) {
const existingFeature = featureUpdates.features.find(x => x.item === f.item.uuid);
existingFeature.item = doc.uuid;
} else {
const replaceIndex = featureUpdates.features.findIndex(x => x === f.uuid);
featureUpdates.features.splice(replaceIndex, 1, doc.uuid);
}
}
await this.updateSource(featureUpdates);
}
}

View file

@ -62,16 +62,37 @@ export default class DHClass extends BaseDataItem {
}
async _preCreate(data, options, user) {
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
if (this.actor?.type === 'character') {
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
if (foundry.utils.getProperty(this.actor, path)) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
return false;
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
if (levelupAuto) {
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
if (foundry.utils.getProperty(this.actor, path)) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
return false;
}
} else {
if (this.actor.system.class.value) {
if (this.actor.system.multiclass.value) {
ui.notifications.warn(
game.i18n.localize('DAGGERHEART.UI.Notifications.multiclassAlreadyPresent')
);
return false;
} else {
const selectedDomain =
await game.system.api.applications.dialogs.MulticlassChoiceDialog.configure(
this.actor,
this
);
if (!selectedDomain) return false;
await this.updateSource({ isMulticlass: true, domains: [selectedDomain] });
}
}
}
}
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
}
_onCreate(data, options, userId) {

View file

@ -23,7 +23,6 @@ export default class DHFeature extends BaseDataItem {
nullable: true,
initial: null
}),
subType: new fields.StringField({ choices: CONFIG.DH.ITEM.featureSubTypes, nullable: true, initial: null }),
originId: new fields.StringField({ nullable: true, initial: null }),
identifier: new fields.StringField()
};

View file

@ -41,27 +41,48 @@ export default class DHSubclass extends BaseDataItem {
}
async _preCreate(data, options, user) {
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
if (this.actor?.type === 'character') {
const classData = this.actor.items.find(
x => x.type === 'class' && x.system.isMulticlass === data.system.isMulticlass
);
const subclassData = this.actor.items.find(
x => x.type === 'subclass' && x.system.isMulticlass === data.system.isMulticlass
);
if (!classData) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
return false;
} else if (subclassData) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassAlreadySelected'));
return false;
} else if (classData.system.subclasses.every(x => x.uuid !== (data.uuid ?? `Item.${data._id}`))) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
return false;
if (this.actor.system.class.subclass) {
if (this.actor.system.multiclass.subclass) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent'));
return false;
} else {
if (!this.actor.system.multiclass.value) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingMulticlass'));
return false;
}
if (
this.actor.system.multiclass.value.system.subclasses.every(
x => x.uuid !== (data.uuid ?? `Item.${data._id}`)
)
) {
ui.notifications.error(
game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInMulticlass')
);
return false;
}
await this.updateSource({ isMulticlass: true });
}
} else {
if (!this.actor.system.class.value) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
return false;
}
if (
this.actor.system.class.value.system.subclasses.every(
x => x.uuid !== (data.uuid ?? `Item.${data._id}`)
)
) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
return false;
}
}
}
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
}
_onCreate(data, options, userId) {

View file

@ -14,6 +14,11 @@ export default class DhAutomation extends foundry.abstract.DataModel {
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.hopeFear.players.label'
})
}),
levelupAuto: new fields.BooleanField({
required: true,
initial: true,
label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.levelupAuto.label'
}),
actionPoints: new fields.BooleanField({
required: true,
initial: false,

View file

@ -172,26 +172,30 @@ export default class DhpActor extends Actor {
}
async levelUp(levelupData) {
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
const levelups = {};
for (var levelKey of Object.keys(levelupData)) {
const level = levelupData[levelKey];
for (var experienceKey in level.achievements.experiences) {
const experience = level.achievements.experiences[experienceKey];
await this.update({
[`system.experiences.${experienceKey}`]: {
name: experience.name,
value: experience.modifier
}
});
if (this.system.companion) {
await this.system.companion.update({
if (levelupAuto) {
for (var experienceKey in level.achievements.experiences) {
const experience = level.achievements.experiences[experienceKey];
await this.update({
[`system.experiences.${experienceKey}`]: {
name: '',
name: experience.name,
value: experience.modifier
}
});
if (this.system.companion) {
await this.system.companion.update({
[`system.experiences.${experienceKey}`]: {
name: '',
value: experience.modifier
}
});
}
}
}
@ -250,74 +254,86 @@ export default class DhpActor extends Actor {
}
for (var addition of featureAdditions) {
for (var featureData of addition.features) {
const feature = new DHFeature({
...featureData,
description: game.i18n.localize(featureData.description)
});
const document = featureData.toPartner && this.system.partner ? this.system.partner : this;
const embeddedItem = await document.createEmbeddedDocuments('Item', [
{
if (levelupAuto) {
for (var featureData of addition.features) {
const feature = new DHFeature({
...featureData,
name: game.i18n.localize(featureData.name),
type: 'feature',
system: feature
}
]);
const newFeature = {
onPartner: Boolean(featureData.toPartner && this.system.partner),
id: embeddedItem[0].id
};
addition.checkbox.features = !addition.checkbox.features
? [newFeature]
: [...addition.checkbox.features, newFeature];
description: game.i18n.localize(featureData.description)
});
const document = featureData.toPartner && this.system.partner ? this.system.partner : this;
const embeddedItem = await document.createEmbeddedDocuments('Item', [
{
...featureData,
name: game.i18n.localize(featureData.name),
type: 'feature',
system: feature
}
]);
const newFeature = {
onPartner: Boolean(featureData.toPartner && this.system.partner),
id: embeddedItem[0].id
};
addition.checkbox.features = !addition.checkbox.features
? [newFeature]
: [...addition.checkbox.features, newFeature];
}
}
selections.push(addition.checkbox);
}
if (multiclass) {
const subclassItem = await foundry.utils.fromUuid(multiclass.secondaryData.subclass);
const subclassData = subclassItem.toObject();
const multiclassItem = await foundry.utils.fromUuid(multiclass.data[0]);
const multiclassData = multiclassItem.toObject();
if (levelupAuto) {
const subclassItem = await foundry.utils.fromUuid(multiclass.secondaryData.subclass);
const subclassData = subclassItem.toObject();
const multiclassItem = await foundry.utils.fromUuid(multiclass.data[0]);
const multiclassData = multiclassItem.toObject();
const embeddedItem = await this.createEmbeddedDocuments('Item', [
{
...multiclassData,
system: {
...multiclassData.system,
domains: [multiclass.secondaryData.domain],
isMulticlass: true
const embeddedItem = await this.createEmbeddedDocuments('Item', [
{
...multiclassData,
system: {
...multiclassData.system,
domains: [multiclass.secondaryData.domain],
isMulticlass: true
}
}
}
]);
]);
await this.createEmbeddedDocuments('Item', [
{
...subclassData,
system: {
...subclassData.system,
isMulticlass: true
await this.createEmbeddedDocuments('Item', [
{
...subclassData,
system: {
...subclassData.system,
isMulticlass: true
}
}
}
]);
selections.push({ ...multiclass, itemUuid: embeddedItem[0].uuid });
]);
selections.push({ ...multiclass, itemUuid: embeddedItem[0].uuid });
} else {
selections.push({ ...multiclass });
}
}
for (var domainCard of domainCards) {
const item = await foundry.utils.fromUuid(domainCard.data[0]);
const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]);
selections.push({ ...domainCard, itemUuid: embeddedItem[0].uuid });
if (levelupAuto) {
const item = await foundry.utils.fromUuid(domainCard.data[0]);
const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]);
selections.push({ ...domainCard, itemUuid: embeddedItem[0].uuid });
} else {
selections.push({ ...domainCard });
}
}
const achievementDomainCards = [];
for (var card of Object.values(level.achievements.domainCards)) {
const item = await foundry.utils.fromUuid(card.uuid);
const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]);
card.itemUuid = embeddedItem[0].uuid;
achievementDomainCards.push(card);
if (levelupAuto) {
for (var card of Object.values(level.achievements.domainCards)) {
const item = await foundry.utils.fromUuid(card.uuid);
const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]);
card.itemUuid = embeddedItem[0].uuid;
achievementDomainCards.push(card);
}
}
if (subclassFeatureState.class) {

View file

@ -263,24 +263,36 @@
gap: 8px;
.experience-container {
position: relative;
display: flex;
align-items: center;
flex-direction: column;
gap: 5px;
.experience-description {
border-color: light-dark(@dark-blue, @golden);
padding-right: 24px;
}
.experience-value {
position: absolute;
right: 0;
width: 22px;
border-left: 1px solid light-dark(@dark-blue, @golden);
height: 100%;
.experience-inner-container {
position: relative;
display: flex;
align-items: center;
justify-content: center;
.experience-description {
border-color: light-dark(@dark-blue, @golden);
padding-right: 24px;
}
.experience-value {
position: absolute;
right: 0;
width: 22px;
border-left: 1px solid light-dark(@dark-blue, @golden);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
textarea {
width: 100%;
resize: none;
border-color: light-dark(@dark-blue, @golden);
}
}
}

View file

@ -24,3 +24,5 @@
@import './dice-roll/roll-selection.less';
@import './damage-reduction/damage-reduction-container.less';
@import './damage-reduction/sheets.less';
@import './multiclass-choice/sheet.less';

View file

@ -104,4 +104,10 @@
}
}
}
.levelup-footer {
display: flex;
gap: 8px;
margin-top: 8px;
}
}

View file

@ -0,0 +1,76 @@
.theme-light .daggerheart.dh-style.dialog.multiclass-choice {
.multiclass-container .domain-choice-container button label {
background-image: url(../assets/parchments/dh-parchment-light.png);
}
}
.daggerheart.dh-style.dialog.multiclass-choice {
.multiclass-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
.multiclass-explanation {
margin-top: 0;
font-style: italic;
}
.multiclass-domains-container {
display: flex;
gap: 16px;
.domain-choice-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
button {
position: relative;
display: flex;
justify-content: center;
width: 120px;
height: 120px;
background: light-dark(@dark-blue-10, @golden-10);
color: light-dark(@dark-blue, @golden);
&.selected {
background: light-dark(@dark-blue-40, @golden-40);
}
label {
position: absolute;
top: 4px;
font-family: @font-body;
border-radius: 6px;
border: 2px solid;
padding: 0 2px;
background-image: url(../assets/parchments/dh-parchment-dark.png);
color: light-dark(@dark, @beige);
}
}
.domain-description {
width: 240px;
display: flex;
flex-wrap: wrap;
font-style: italic;
border: 1px solid light-dark(@dark-blue, @golden);
border-radius: 6px;
padding: 4px 4px;
}
}
}
footer {
width: 100%;
display: flex;
gap: 8px;
button {
flex: 1;
}
}
}
}

View file

@ -5,22 +5,26 @@
border: 1px solid light-dark(@dark-blue, @golden);
input[type='text'],
input[type='number'] {
input[type='number'],
textarea {
background: light-dark(transparent, transparent);
border-radius: 6px;
box-shadow: 0 4px 30px @soft-shadow;
backdrop-filter: blur(9.5px);
-webkit-backdrop-filter: blur(9.5px);
outline: none;
outline: 2px solid transparent;
color: light-dark(@dark-blue, @golden);
border: 1px solid light-dark(@dark, @beige);
transition: all 0.3s ease;
&::placeholder {
color: light-dark(@dark-40, @beige-50);
}
&:hover,
&:hover[type='text'],
&:hover[type='number'],
&:focus,
&:focus[type='text'],
&:focus[type='number'] {
background: light-dark(@soft-shadow, @semi-transparent-dark-blue);
@ -70,6 +74,13 @@
}
}
textarea {
color: light-dark(@dark, @beige);
font-family: @font-body;
scrollbar-width: thin;
scrollbar-color: light-dark(@dark-blue, @golden) transparent;
}
button {
background: light-dark(transparent, @golden);
border: 1px solid light-dark(@dark-blue, @dark-blue);
@ -206,6 +217,10 @@
}
}
&.inactive {
opacity: 0.5;
}
&.fit-height {
height: 95%;
}

View file

@ -12,18 +12,33 @@
.experience-list {
display: flex;
flex-direction: column;
gap: 10px;
gap: 15px;
}
.experience-item {
.experience-item {
display: flex;
flex-direction: column;
gap: 5px;
.experience-inner-item {
display: grid;
grid-template-columns: 3fr 1fr 30px;
align-items: center;
gap: 5px;
&.no-controls {
grid-template-columns: 3fr 1fr;
}
a {
text-align: center;
}
}
textarea {
width: 100%;
resize: none;
}
}
}
}

View file

@ -0,0 +1,36 @@
.application.daggerheart.dh-style.dialog {
.tab.details {
.traits-inner-container {
width: 100%;
display: flex;
align-items: center;
justify-content: space-evenly;
gap: 8px;
.trait-container {
width: 60px;
height: 60px;
background: url(../assets/svg/trait-shield.svg) no-repeat;
display: flex;
flex-direction: column;
align-items: center;
div {
filter: drop-shadow(0 0 3px black);
text-shadow: 0 0 3px black;
font-family: @font-body;
font-size: 12px;
}
input {
text-align: center;
width: 32px;
height: 24px;
position: relative;
top: 2px;
padding: 0;
}
}
}
}
}

View file

@ -2,6 +2,7 @@
@import './adversary-settings/sheet.less';
@import './adversary-settings/experiences.less';
@import './adversary-settings/features.less';
@import './character-settings/sheet.less';
@import './environment-settings/features.less';
@import './environment-settings/adversaries.less';

View file

@ -4,12 +4,24 @@
// Theme header backgrounds
.appTheme({
.character-header-sheet .trait {
background: url(../assets/svg/trait-shield.svg) no-repeat;
.character-header-sheet {
.trait {
background: url(../assets/svg/trait-shield.svg) no-repeat;
}
.character-row .domains-section img {
filter: invert(88%) sepia(98%) saturate(1784%) hue-rotate(311deg) brightness(104%) contrast(91%);
}
}
}, {
.character-header-sheet .trait {
.character-header-sheet {
.trait {
background: url('../assets/svg/trait-shield-light.svg') no-repeat;
}
.character-row .domains-section img {
filter: invert(87%) sepia(15%) saturate(343%) hue-rotate(333deg) brightness(110%) contrast(87%);
}
}
});
@ -88,6 +100,11 @@
font-size: 12px;
color: light-dark(@dark-blue, @golden);
.missing-header-feature {
opacity: 0.5;
text-decoration: line-through;
}
span {
padding: 3px;
border-radius: 3px;
@ -107,14 +124,27 @@
.character-row {
display: flex;
gap: 20px;
align-items: center;
justify-content: space-between;
padding: 0;
margin-bottom: 15px;
.hope-section {
margin-right: 20px;
}
.downtime-section {
display: flex;
align-items: center;
gap: 2px;
margin-left: auto;
button {
flex: 1;
}
}
.hope-section,
.threshold-section {
.domains-section {
position: relative;
display: flex;
gap: 10px;
@ -132,21 +162,24 @@
font-weight: bold;
text-transform: uppercase;
color: light-dark(@dark-blue, @golden);
&.threshold-value {
color: light-dark(@dark, @beige);
}
}
.threshold-legend {
position: absolute;
bottom: -21px;
color: light-dark(@golden, @dark-blue);
background-color: light-dark(@dark-blue, @golden);
padding: 3px;
justify-self: anchor-center;
border-radius: 0 0 3px 3px;
text-transform: capitalize;
.domain {
display: flex;
align-items: center;
gap: 5px;
.label {
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
color: light-dark(@dark-blue, @golden);
}
img {
height: 20px;
width: 20px;
}
}
.hope-value {
@ -193,14 +226,5 @@
}
}
}
.character-downtime-container {
display: flex;
gap: 2px;
button {
flex: 1;
}
}
}
}

View file

@ -18,6 +18,7 @@
}
.character-header-sheet {
position: relative;
grid-row: 1;
grid-column: 2;
}

View file

@ -55,6 +55,62 @@
}
}
}
.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: 14px;
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 {
@ -62,12 +118,13 @@
display: flex;
flex-direction: column;
top: -20px;
gap: 30px;
gap: 10px;
margin-bottom: -16px;
.resources-section {
display: flex;
justify-content: space-evenly;
margin-bottom: 20px;
.status-bar {
display: flex;
@ -345,6 +402,32 @@
}
}
}
.threshold-section {
position: relative;
display: flex;
align-self: center;
gap: 10px;
background-color: light-dark(transparent, @dark-blue);
color: light-dark(@dark-blue, @golden);
padding: 5px 10px;
border: 1px solid light-dark(@dark-blue, @golden);
border-radius: 6px;
align-items: center;
width: fit-content;
height: 30px;
h4 {
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
color: light-dark(@dark-blue, @golden);
&.threshold-value {
color: light-dark(@dark, @beige);
}
}
}
}
.items-sidebar-list {
@ -360,7 +443,7 @@
.shortcut-items-section {
overflow-y: hidden;
max-height: 56%;
padding-top: 16px;
padding-top: 10px;
padding-bottom: 20px;
mask-image: linear-gradient(0deg, transparent 0%, black 5%, black 95%, transparent 100%);
@ -393,35 +476,24 @@
.experience-row {
display: flex;
gap: 5px;
width: 250px;
align-items: center;
justify-content: space-between;
input[type='text'] {
height: 32px;
width: 180px;
border: 1px solid transparent;
outline: 2px solid transparent;
.experience-value {
height: 25px;
width: 35px;
font-size: 14px;
font-family: @font-body;
transition: all 0.3s ease;
color: light-dark(@dark, @beige);
&:hover {
outline: 2px solid light-dark(@dark, @beige);
}
align-content: center;
text-align: center;
margin-right: 5px;
}
}
.experience-value {
height: 25px;
width: 35px;
font-size: 14px;
font-family: @font-body;
color: light-dark(@dark, @beige);
align-content: center;
text-align: center;
.controls {
margin-left: auto;
}
}
}
}

View file

@ -9,8 +9,12 @@
<div class="experiences-inner-container">
{{#each experience.values as |experience id|}}
<div class="experience-container">
<input class="experience-description" type="text" name="{{concat "experiences." id ".name" }}" value="{{experience.name}}" placeholder="{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.newExperience"}}" />
<div class="experience-value">{{numberFormat this.value sign=true}}</div>
<div class="experience-inner-container">
<input class="experience-description" type="text" name="{{concat "experiences." id ".name" }}" value="{{experience.name}}" placeholder="{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.newExperience"}}" />
<div class="experience-value">{{numberFormat this.value sign=true}}</div>
</div>
<textarea name="{{concat "experiences." id ".description"}}">{{experience.description}}</textarea>
</div>
{{/each}}
</div>

View file

@ -0,0 +1,23 @@
<div>
<div class="multiclass-container">
<h5 class="multiclass-explanation">{{localize "DAGGERHEART.APPLICATIONS.MulticlassChoice.explanation" class=multiclass.parent.name }}</h5>
<h5 class="multiclass-explanation">{{localize "DAGGERHEART.APPLICATIONS.MulticlassChoice.selectDomainPrompt" }}</h5>
<div class="multiclass-domains-container">
{{#each domainChoices as | choice |}}
<div class="domain-choice-container">
<button data-action="selectDomain" data-domain="{{choice.value}}" {{#if choice.selected}}class="selected"{{/if}} {{disabled choice.disabled}}>
<label>{{choice.label}}</label>
<img src="{{choice.src}}" />
</button>
<div class="domain-description">{{choice.description}}</div>
</div>
{{/each}}
</div>
<footer>
<button data-action="close">{{localize "Cancel"}}</button>
<button data-action="save" {{disabled multiclassDisabled}}>{{localize "DAGGERHEART.GENERAL.multiclass"}}</button>
</footer>
</div>
</div>

View file

@ -0,0 +1,8 @@
<section class='tab-footer'>
{{#unless levelupAuto}}
<div class="levelup-footer">
<button type="button" data-action="close">{{localize "Cancel"}}</button>
<button type="button" data-action="save">{{localize "Save"}}</button>
</div>
{{/unless}}
</section>

View file

@ -1,40 +1,44 @@
<section class='tab-navigation'>
<line-div></line-div>
<div class="levelup-navigation-container">
{{#if this.showTabs}}
<nav class='feature-tab sheet-tabs tabs' data-group='primary'>
{{#each tabs as |tab|}}
{{#if (not (eq tab.id 'summary'))}}
<div class="levelup-tab-container">
<a class='{{tab.id}} {{tab.cssClass}}' data-action='tab' data-group='{{tab.group}}' data-tab='{{tab.id}}'>
{{localize tab.label}}
</a>
{{#if tab.progress}}
<div>{{tab.progress.selected}}/{{tab.progress.max}}</div>
{{/if}}
</div>
{{/if}}
{{/each}}
</nav>
{{/if}}
<div class="levelup-navigation-actions {{#if (not this.showTabs)}}test{{/if}}">
{{#if this.navigate.previous.fromSummary}}
<button data-action="activatePart" data-part="advancements">{{localize "DAGGERHEART.APPLICATIONS.Levelup.navigateToLevelup"}}</button>
{{else}}
{{#if (not this.navigate.previous.disabled)}}
<button data-action="updateCurrentLevel" >{{this.navigate.previous.label}}</button>
{{/if}}
{{#if levelupAuto}}
<line-div></line-div>
<div class="levelup-navigation-container">
{{#if this.showTabs}}
<nav class='feature-tab sheet-tabs tabs' data-group='primary'>
{{#each tabs as |tab|}}
{{#if (not (eq tab.id 'summary'))}}
<div class="levelup-tab-container">
<a class='{{tab.id}} {{tab.cssClass}}' data-action='tab' data-group='{{tab.group}}' data-tab='{{tab.id}}'>
{{localize tab.label}}
</a>
{{#if tab.progress}}
<div>{{tab.progress.selected}}/{{tab.progress.max}}</div>
{{/if}}
</div>
{{/if}}
{{/each}}
</nav>
{{/if}}
{{#if this.navigate.next.show}}
{{#if this.navigate.next.toSummary}}
<button data-action="activatePart" data-part="summary" {{#if this.navigate.next.disabled}}disabled{{/if}}>{{localize "DAGGERHEART.APPLICATIONS.Levelup.navigateToSummary"}}</button>
{{else}}
<button data-action="updateCurrentLevel" data-forward="true" {{#if this.navigate.next.disabled}}disabled{{/if}}>{{this.navigate.next.label}}</button>
{{/if}}
{{else}}
<div></div>
{{#if this.levelupAuto}}
<div class="levelup-navigation-actions {{#if (not this.showTabs)}}test{{/if}}">
{{#if this.navigate.previous.fromSummary}}
<button data-action="activatePart" data-part="advancements">{{localize "DAGGERHEART.APPLICATIONS.Levelup.navigateToLevelup"}}</button>
{{else}}
{{#if (not this.navigate.previous.disabled)}}
<button data-action="updateCurrentLevel" >{{this.navigate.previous.label}}</button>
{{/if}}
{{/if}}
{{#if this.navigate.next.show}}
{{#if this.navigate.next.toSummary}}
<button data-action="activatePart" data-part="summary" {{#if this.navigate.next.disabled}}disabled{{/if}}>{{localize "DAGGERHEART.APPLICATIONS.Levelup.navigateToSummary"}}</button>
{{else}}
<button data-action="updateCurrentLevel" data-forward="true" {{#if this.navigate.next.disabled}}disabled{{/if}}>{{this.navigate.next.label}}</button>
{{/if}}
{{else}}
<div></div>
{{/if}}
</div>
{{/if}}
</div>
</div>
<line-div></line-div>
<line-div></line-div>
{{/if}}
</section>

View file

@ -11,6 +11,7 @@
{{formGroup settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints localize=true}}
{{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}}
{{formGroup settingFields.schema.fields.effects.fields.rangeDependent value=settingFields._source.effects.rangeDependent localize=true}}
{{formGroup settingFields.schema.fields.levelupAuto value=settingFields._source.levelupAuto localize=true}}
<footer class="form-footer">
<button data-action="reset">

View file

@ -12,9 +12,13 @@
<ul class="experience-list">
{{#each document.system.experiences as |experience key|}}
<li class="experience-item">
<input class="name" type="text" name="system.experiences.{{key}}.name" value="{{experience.name}}" />
<input class="modifier" type="text" name="system.experiences.{{key}}.value" value="{{experience.value}}" data-dtype="Number" />
<a data-action="removeExperience" data-experience="{{key}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a>
<div class="experience-inner-item">
<input class="name" type="text" name="system.experiences.{{key}}.name" value="{{experience.name}}" />
<input class="modifier" type="text" name="system.experiences.{{key}}.value" value="{{experience.value}}" data-dtype="Number" />
<a data-action="removeExperience" data-experience="{{key}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a>
</div>
<textarea name="system.experiences.{{key}}.description">{{experience.description}}</textarea>
</li>
{{/each}}
</ul>

View file

@ -0,0 +1,42 @@
<section
class='tab {{tabs.details.cssClass}} {{tabs.details.id}}'
data-tab='{{tabs.details.id}}'
data-group='{{tabs.details.group}}'
>
<fieldset class="one-column">
<legend>{{localize 'DAGGERHEART.GENERAL.Trait.plural'}}</legend>
<div class="nest-inputs">
<div class="traits-inner-container">
{{#each document._source.system.traits as | trait key |}}
<div class="trait-container">
<div>{{localize (concat "DAGGERHEART.CONFIG.Traits." key ".name" )}}</div>
<input type="text" data-dtype="Number" name="{{concat "system.traits." key ".value"}}" value="{{trait.value}}" />
</div>
{{/each}}
</div>
</div>
</fieldset>
<fieldset class="one-column">
<legend>{{localize 'DAGGERHEART.GENERAL.basics'}}</legend>
<div class="two-columns even">
{{formGroup systemFields.resources.fields.hitPoints.fields.value value=document._source.system.resources.hitPoints.value localize=true}}
<span data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.maxHPClassBound"}}">
{{formGroup systemFields.resources.fields.hitPoints.fields.max value=document._source.system.resources.hitPoints.max localize=true}}
</span>
{{formGroup systemFields.resources.fields.stress.fields.value value=document._source.system.resources.stress.value localize=true}}
{{formGroup systemFields.resources.fields.stress.fields.max value=document._source.system.resources.stress.max localize=true}}
{{formGroup systemFields.resources.fields.hope.fields.value value=document._source.system.resources.hope.value localize=true}}
{{formGroup systemFields.resources.fields.hope.fields.max value=document._source.system.resources.hope.max localize=true}}
{{formGroup systemFields.proficiency value=document._source.system.proficiency localize=true}}
<span data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.maxEvasionClassBound"}}">
{{formGroup systemFields.evasion value=document._source.system.evasion label="DAGGERHEART.ACTORS.Character.maxEvasionBonus" localize=true}}
</span>
</div>
</fieldset>
</section>

View file

@ -0,0 +1,25 @@
<section
class='tab {{tabs.experiences.cssClass}} {{tabs.experiences.id}}'
data-tab='{{tabs.experiences.id}}'
data-group='{{tabs.experiences.group}}'
>
<button type="button" class="add-experience-btn" type="button" data-action="addExperience">
<span>{{localize "DOCUMENT.New" type=(localize "DAGGERHEART.GENERAL.experience.single")}}</span>
</button>
<fieldset>
<legend>{{localize tabs.experiences.label}}</legend>
<ul class="experience-list">
{{#each document._source.system.experiences as |experience key|}}
<li class="experience-item">
<div class="experience-inner-item {{#if @root.levelupAuto}}no-controls{{/if}}">
<input class="name" type="text" name="system.experiences.{{key}}.name" value="{{experience.name}}" />
<input class="modifier" type="text" name="system.experiences.{{key}}.value" value="{{experience.value}}" data-dtype="Number" />
{{#unless @root.levelupAuto}}<a data-action="removeExperience" data-experience="{{key}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a>{{/unless}}
</div>
<textarea name="system.experiences.{{key}}.description">{{experience.description}}</textarea>
</li>
{{/each}}
</ul>
</fieldset>
</section>

View file

@ -0,0 +1,3 @@
<header class="dialog-header">
<h1>{{document.name}}</h1>
</header>

View file

@ -18,4 +18,5 @@
{{/if}}
{{/if}}
</fieldset>
{{> 'systems/daggerheart/templates/actionTypes/damage.hbs' fields=systemFields.attack.fields.damage.fields.parts.element.fields source=document.system.attack.damage path="system.attack."}}
</section>

View file

@ -3,16 +3,24 @@
data-tab='{{tabs.experiences.id}}'
data-group='{{tabs.experiences.group}}'
>
<button type="button" class="add-experience-btn" type="button" data-action="addExperience">
<span>{{localize "DOCUMENT.New" type=(localize "DAGGERHEART.GENERAL.experience.single")}}</span>
</button>
<fieldset>
<legend>{{localize tabs.experiences.label}}</legend>
<ul class="experience-list">
{{#each document.system.experiences as |experience key|}}
{{#each document._source.system.experiences as |experience key|}}
<li class="experience-item">
<input class="name" type="text" name="system.experiences.{{key}}.name" value="{{experience.name}}" />
<input disabled class="modifier" type="text" name="system.experiences.{{key}}.value" value="{{experience.value}}" data-dtype="Number" />
<div class="experience-inner-item {{#if @root.levelupAuto}}no-controls{{/if}}">
<input class="name" type="text" name="system.experiences.{{key}}.name" value="{{experience.name}}" />
<input class="modifier" type="text" name="system.experiences.{{key}}.value" value="{{experience.value}}" data-dtype="Number" />
{{#unless @root.levelupAuto}}<a data-action="removeExperience" data-experience="{{key}}" data-tooltip="{{localize 'CONTROLS.CommonDelete'}}"><i class="fa-solid fa-trash"></i></a>{{/unless}}
</div>
<textarea name="system.experiences.{{key}}.description">{{experience.description}}</textarea>
</li>
{{/each}}
</ul>
</fieldset>
</section>

View file

@ -36,7 +36,7 @@
<div class="adversary-navigation">
{{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
<button data-action="openSettings">
<button data-action="openSettings" data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.openSheetSettings"}}">
<i class="fa-solid fa-wrench"></i>
</button>
</div>

View file

@ -98,17 +98,17 @@
</div>
<div class="experience-list">
{{#each source.system.experiences as |experience id|}}
<div class="experience-row">
<div class="experience-value">
+{{experience.value}}
<div class="experience-row" data-tooltip-text="{{experience.description}}">
<div class="experience-value">
+{{experience.value}}
</div>
<span class="experience-name">{{experience.name}}</span>
<div class="controls">
<a data-action="sendExpToChat" data-id="{{id}}">
<i class="fa-regular fa-message"></i>
</a>
</div>
</div>
<span class="experience-name">{{experience.name}}</span>
<div class="controls">
<a data-action="sendExpToChat" data-id="{{id}}">
<i class="fa-regular fa-message"></i>
</a>
</div>
</div>
{{/each}}
</div>
</div>

View file

@ -18,7 +18,7 @@
class="level-button glow" data-tooltip="{{#if document.system.needsCharacterSetup}}{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.buttonTitle"}}{{else}}{{localize "DAGGERHEART.ACTORS.Character.levelUp"}}{{/if}}"
data-action="levelManagement"
>
<i class="fa-solid fa-triangle-exclamation"></i>
<i class="fa-solid fa-angles-up"></i>
</button>
{{/if}}
{{localize 'DAGGERHEART.GENERAL.level'}}
@ -31,25 +31,25 @@
{{#if document.system.class.value}}
<span data-action="editDoc" data-item-uuid="{{document.system.class.value.uuid}}">{{document.system.class.value.name}}</span>
{{else}}
<span data-action="openPack" data-key="daggerheart.classes">{{localize 'TYPES.Item.class'}}</span>
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.classes">{{localize 'TYPES.Item.class'}}</span>
{{/if}}
<span class="dot">•</span>
{{#if document.system.class.subclass}}
<span data-action="editDoc" data-item-uuid="{{document.system.class.subclass.uuid}}">{{document.system.class.subclass.name}}</span>
{{else}}
<span data-action="openPack" data-key="daggerheart.subclass">{{localize 'TYPES.Item.subclass'}}</span>
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.subclasses">{{localize 'TYPES.Item.subclass'}}</span>
{{/if}}
<span class="dot">•</span>
{{#if document.system.community}}
<span data-action="editDoc" data-item-uuid="{{document.system.community.uuid}}">{{document.system.community.name}}</span>
{{else}}
<span data-action="openPack" data-key="daggerheart.community">{{localize 'TYPES.Item.community'}}</span>
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.communities">{{localize 'TYPES.Item.community'}}</span>
{{/if}}
<span class="dot">•</span>
{{#if document.system.ancestry}}
<span data-action="editDoc" data-item-uuid="{{document.system.ancestry.uuid}}">{{document.system.ancestry.name}}</span>
{{else}}
<span data-action="openPack" data-key="daggerheart.ancestry">{{localize 'TYPES.Item.ancestry'}}</span>
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.ancestries">{{localize 'TYPES.Item.ancestry'}}</span>
{{/if}}
</div>
@ -64,7 +64,7 @@
{{#if document.system.multiclass.subclass}}
<span data-action="editDoc" data-item-uuid="{{document.system.multiclass.subclass.uuid}}">{{document.system.multiclass.subclass.name}}</span>
{{else}}
<span data-action="openPack" data-key="daggerheart.subclass">{{localize 'TYPES.Item.subclass'}}</span>
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.subclasses">{{localize 'TYPES.Item.subclass'}}</span>
{{/if}}
</div>
{{/if}}
@ -85,12 +85,23 @@
</span>
{{/times}}
</div>
<div class="threshold-section">
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}</h4>
<h4 class="threshold-value">{{document.system.damageThresholds.major}}</h4>
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}</h4>
<h4 class="threshold-value">{{document.system.damageThresholds.severe}}</h4>
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}</h4>
{{#if document.system.class.value}}
<div class="domains-section">
{{#each document.system.class.value.system.domains as |domain|}}
<div class="domain">
<span class="label">{{localize (concat 'DAGGERHEART.GENERAL.Domain.' domain '.label')}}</span>
<img src="{{concat 'systems/daggerheart/assets/icons/domains/' domain '.svg'}}" alt="">
</div>
{{/each}}
</div>
{{/if}}
<div class="downtime-section">
<button type="button" data-action="useDowntime" data-type="shortRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}">
<i class="fa-solid fa-utensils"></i>
</button>
<button type="button" data-action="useDowntime" data-type="longRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}}">
<i class="fa-solid fa-bed"></i>
</button>
</div>
</div>
@ -117,13 +128,6 @@
</div>
{{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
<div class="character-downtime-container">
<button type="button" data-action="useDowntime" data-type="shortRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}">
<i class="fa-solid fa-chair"></i>
</button>
<button type="button" data-action="useDowntime" data-type="longRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}}">
<i class="fa-solid fa-bed"></i>
</button>
</div>
<button data-action="openSettings" data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.openSheetSettings"}}"><i class="fa-solid fa-wrench"></i></button>
{{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
</header>

View file

@ -1,6 +1,17 @@
<aside class="character-sidebar-sheet">
<div class="portrait {{#if isDeath}}death-roll{{/if}}">
<img src="{{document.img}}" alt="{{document.name}}" data-action='editImage' data-edit="img">
{{#if document.system.class.subclass.system.spellcastingTrait}}
<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.class.subclass.system.spellcastingTrait '.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
isDeath}}data-action="makeDeathMove" {{/if}}><i class="fas fa-skull death-save"></i></a>
</div>
@ -87,6 +98,13 @@
</div>
</div>
</div>
<div class="threshold-section">
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.minor"}}</h4>
<h4 class="threshold-value">{{document.system.damageThresholds.major}}</h4>
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.major"}}</h4>
<h4 class="threshold-value">{{document.system.damageThresholds.severe}}</h4>
<h4 class="threshold-label">{{localize "DAGGERHEART.GENERAL.DamageThresholds.severe"}}</h4>
</div>
</div>
<div class="shortcut-items-section">
@ -142,18 +160,17 @@
</div>
<div class="experience-list">
{{#each document.system.experiences as |experience id|}}
<div class="experience-row">
<div class="experience-value">
+{{experience.value}}
<div class="experience-row" data-tooltip-text="{{experience.description}}">
<div class="experience-value">
+{{experience.value}}
</div>
<span>{{experience.name}}</span>
<div class="controls">
<a data-action="sendExpToChat" data-type="experience" data-id="{{id}}">
<i class="fa-regular fa-message"></i>
</a>
</div>
</div>
<input name="system.experiences.{{id}}.name" data-experience={{id}}
value="{{experience.name}}" type="text" />
<div class="controls">
<a data-action="sendExpToChat" data-type="experience" data-id="{{id}}">
<i class="fa-regular fa-message"></i>
</a>
</div>
</div>
{{/each}}
</div>
</div>

View file

@ -39,7 +39,7 @@
</div>
<div class="companion-navigation">
{{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
<button type="button" data-action="openSettings">
<button type="button" data-action="openSettings" data-tooltip-text="{{localize "DAGGERHEART.UI.Tooltip.openSheetSettings"}}">
<i class="fa-solid fa-wrench"></i>
</button>
</div>

View file

@ -23,38 +23,40 @@
</fieldset>
</div>
<fieldset>
<legend>{{localize "TYPES.Item.subclass"}}</legend>
<div class="feature-list">
{{#each source.system.subclasses as |subclass index|}}
<li class='feature-item'>
<div class='feature-line'>
<img class='image' src='{{subclass.img}}' />
<h4>
{{subclass.name}}
</h4>
<div class='controls'>
<a
class='effect-control'
data-action='editDoc'
data-item-uuid={{subclass.uuid}}
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
>
<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>
{{#unless (eq document.parent.type 'character')}}
<fieldset>
<legend>{{localize "TYPES.Item.subclass"}}</legend>
<div class="feature-list">
{{#each source.system.subclasses as |subclass index|}}
<li class='feature-item'>
<div class='feature-line'>
<img class='image' src='{{subclass.img}}' />
<h4>
{{subclass.name}}
</h4>
<div class='controls'>
<a
class='effect-control'
data-action='editDoc'
data-item-uuid={{subclass.uuid}}
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
>
<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>
</div>
</div>
</div>
</li>
{{/each}}
</div>
</fieldset>
</li>
{{/each}}
</div>
</fieldset>
{{/unless}}
</div>

View file

@ -31,10 +31,10 @@
<span>{{localize "DAGGERHEART.CONFIG.Traits.knowledge.name"}}</span>
<input type="text" name="system.characterGuide.suggestedTraits.knowledge" value="{{source.system.characterGuide.suggestedTraits.knowledge}}" />
</fieldset>
<fieldset class="one-column">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedEquipment"}}</legend>
<fieldset class="one-column drop-section primary-weapon-section">
<fieldset class="one-column drop-section primary-weapon-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedPrimaryWeaponTitle"}}</legend>
<div class="drop-section-body list-items">
{{#if document.system.characterGuide.suggestedPrimaryWeapon}}
@ -42,14 +42,14 @@
<img class="image" src="{{document.system.characterGuide.suggestedPrimaryWeapon.img}}" />
<span>{{document.system.characterGuide.suggestedPrimaryWeapon.name}}</span>
<div class="controls">
<a data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}
</div>
</fieldset>
<fieldset class="one-column drop-section secondary-weapon-section">
<fieldset class="one-column drop-section secondary-weapon-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedSecondaryWeaponTitle"}}</legend>
<div class="drop-section-body list-items">
{{#if document.system.characterGuide.suggestedSecondaryWeapon}}
@ -57,14 +57,14 @@
<img class="image" src="{{document.system.characterGuide.suggestedSecondaryWeapon.img}}" />
<span>{{document.system.characterGuide.suggestedSecondaryWeapon.name}}</span>
<div class="controls">
<a data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}
</div>
</fieldset>
<fieldset class="one-column drop-section armor-section">
<fieldset class="one-column drop-section armor-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.suggestedArmorTitle"}}</legend>
<div class="drop-section-body list-items">
{{#if document.system.characterGuide.suggestedArmor}}
@ -72,7 +72,7 @@
<img class="image" src="{{document.system.characterGuide.suggestedArmor.img}}" />
<span>{{document.system.characterGuide.suggestedArmor.name}}</span>
<div class="controls">
<a data-action="removeSuggestedItem" data-target="suggestedArmor"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeSuggestedItem" data-target="suggestedArmor"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}
@ -82,7 +82,7 @@
<fieldset class="one-column">
<legend>{{localize "DAGGERHEART.GENERAL.inventory"}}</legend>
<fieldset class="one-column drop-section take-section">
<fieldset class="one-column drop-section take-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.GENERAL.take"}}</legend>
<div class="drop-section-body list-items">
{{#each source.system.inventory.take}}
@ -91,7 +91,7 @@
<img class="image" src="{{this.img}}" />
<span>{{this.name}}</span>
<div class="controls">
<a data-action="removeItemFromCollection" data-target="inventory.take" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeItemFromCollection" data-target="inventory.take" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}
@ -99,7 +99,7 @@
</div>
</fieldset>
<fieldset class="one-column drop-section choice-a-section">
<fieldset class="one-column drop-section choice-a-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.thenChoose"}}</legend>
<div class="drop-section-body list-items">
{{#each source.system.inventory.choiceA}}
@ -108,7 +108,7 @@
<img class="image" src="{{this.img}}" />
<span>{{this.name}}</span>
<div class="controls">
<a data-action="removeItemFromCollection" data-target="inventory.choiceA" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeItemFromCollection" data-target="inventory.choiceA" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}
@ -116,7 +116,7 @@
</div>
</fieldset>
<fieldset class="one-column drop-section choice-b-section">
<fieldset class="one-column drop-section choice-b-section {{#if (eq document.parent.type 'character')}}inactive{{/if}}">
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.andEither"}}</legend>
<div class="drop-section-body list-items">
{{#each source.system.inventory.choiceB}}
@ -125,7 +125,7 @@
<img class="image" src="{{this.img}}" />
<span>{{this.name}}</span>
<div class="controls">
<a data-action="removeItemFromCollection" data-target="inventory.choiceB" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>
{{#unless (eq document.parent.type 'character')}}<a data-action="removeItemFromCollection" data-target="inventory.choiceB" data-uuid="{{this.uuid}}"><i class="fa-solid fa-trash icon-button"></i></a>{{/unless}}
</div>
</div>
{{/if}}