[Feature] Loadout&Domains Homebrew (#529)

* Removed ChatTheme from settings

* 0 or blank loadoutSize now means unlimited

* Added Homebrew maxDomains
This commit is contained in:
WBHarry 2025-08-02 22:36:21 +02:00 committed by GitHub
parent 2e5337c5c5
commit ee5c3a9322
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 74 additions and 65 deletions

View file

@ -8,7 +8,6 @@ import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs';
import { DualityRollColor } from './module/data/settings/Appearance.mjs';
import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/dice/_module.mjs';
import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs';
import { registerCountdownHooks } from './module/data/countdowns.mjs';
@ -56,8 +55,8 @@ Hooks.once('init', () => {
};
CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, DHRoll, DualityRoll, D20Roll, DamageRoll];
Roll.CHAT_TEMPLATE = "systems/daggerheart/templates/ui/chat/foundryRoll.hbs";
Roll.TOOLTIP_TEMPLATE = "systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs";
Roll.CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRoll.hbs';
Roll.TOOLTIP_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs';
CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate;
const { DocumentSheetConfig } = foundry.applications.apps;
@ -162,12 +161,6 @@ Hooks.on('ready', () => {
if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear !== 'hide')
ui.resources.render({ force: true });
document.body.classList.toggle(
'theme-colorful',
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
DualityRollColor.colorful.value
);
registerCountdownHooks();
socketRegistration.registerSocketHooks();
registerRollDiceHooks();

View file

@ -2077,12 +2077,6 @@
}
}
},
"DualityRollColor": {
"options": {
"colorful": "Colorful",
"normal": "Normal"
}
},
"Homebrew": {
"newDowntimeMove": "Downtime Move",
"downtimeMoves": "Downtime Moves",
@ -2092,7 +2086,11 @@
"FIELDS": {
"maxFear": { "label": "Max Fear" },
"traitArray": { "label": "Initial Trait Modifiers" },
"maxLoadout": { "label": "Max Cards in Loadout" }
"maxLoadout": {
"label": "Max Cards in Loadout",
"hint": "Set to blank or 0 for unlimited maximum"
},
"maxDomains": { "label": "Max Class Domains", "hint": "Max domains you can set on a class" }
},
"currency": {
"enabled": "Enable Overrides",
@ -2282,7 +2280,8 @@
"beastformToManyAdvantages": "You cannot select any more advantages.",
"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.",
"loadoutMaxReached": "You've reached maximum loadout. Move atleast one domain card to the vault, or increase the limit in homebrew settings if desired.",
"domainMaxReached": "You've reached the maximum domains for the class. Increase the limit in homebrew settings if desired.",
"insufficientResources": "You have insufficient resources",
"multiclassAlreadyPresent": "You already have a class and multiclass",
"subclassesAlreadyPresent": "You already have a class and multiclass subclass"

View file

@ -1,4 +1,4 @@
import DhAppearance, { DualityRollColor } from '../../data/settings/Appearance.mjs';
import DhAppearance from '../../data/settings/Appearance.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -96,11 +96,6 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
static async save() {
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, this.settings.toObject());
document.body.classList.toggle(
'theme-colorful',
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).dualityColorScheme ===
DualityRollColor.colorful.value
);
this.close();
}

View file

@ -266,9 +266,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const doc = await getDocFromElement(target);
const actorLoadout = doc.actor.system.loadoutSlot;
if (actorLoadout.available) return doc.update({ 'system.inVault': false });
ui.notifications.warn(
game.i18n.format('DAGGERHEART.UI.Notifications.loadoutMaxReached', { max: actorLoadout.max })
);
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached'));
}
},
{
@ -686,6 +684,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
*/
static async #toggleVault(_event, button) {
const doc = await getDocFromElement(button);
const { available } = this.document.system.loadoutSlot;
if (doc.system.inVault && !available) {
return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached'));
}
await doc?.update({ 'system.inVault': !doc.system.inVault });
}

View file

@ -15,7 +15,10 @@ export default class ClassSheet extends DHBaseItemSheet {
{
selector: '.domain-input',
options: () => CONFIG.DH.DOMAIN.domains,
callback: ClassSheet.#onDomainSelect
callback: ClassSheet.#onDomainSelect,
tagifyOptions: {
maxTags: () => game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxDomains
}
}
],
dragDrop: [

View file

@ -29,14 +29,3 @@ export const gameSettings = {
LevelTiers: 'LevelTiers',
Countdowns: 'Countdowns'
};
export const DualityRollColor = {
colorful: {
value: 0,
label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.colorful'
},
normal: {
value: 1,
label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.normal'
}
};

View file

@ -362,13 +362,12 @@ export default class DhCharacter extends BaseDataActor {
get loadoutSlot() {
const loadoutCount = this.domainCards.loadout?.length ?? 0,
max =
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout +
this.bonuses.maxLoadout;
worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout,
max = !worldSetting ? null : worldSetting + this.bonuses.maxLoadout;
return {
current: loadoutCount,
available: Math.max(max - loadoutCount, 0),
available: !max ? true : Math.max(max - loadoutCount, 0),
max
};
}

View file

@ -19,7 +19,7 @@ export default class DHClass extends BaseDataItem {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
domains: new fields.ArrayField(new fields.StringField()),
classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
hitPoints: new fields.NumberField({
required: true,
@ -123,6 +123,14 @@ export default class DHClass extends BaseDataItem {
const allowed = await super._preUpdate(changed, options, userId);
if (allowed === false) return false;
if (changed.system?.domains) {
const maxDomains = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxDomains;
if (changed.system.domains.length > maxDomains) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.domainMaxReached'));
return false;
}
}
const paths = [
'subclasses',
'characterGuide.suggestedPrimaryWeapon',

View file

@ -10,12 +10,6 @@ export default class DhAppearance extends foundry.abstract.DataModel {
initial: fearDisplay.token.value,
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.displayFear.label'
}),
dualityColorScheme: new fields.StringField({
required: true,
choices: DualityRollColor,
initial: DualityRollColor.normal.value,
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.dualityColorScheme.label'
}),
diceSoNice: new fields.SchemaField({
hope: new fields.SchemaField({
foreground: new fields.ColorField({ required: true, initial: '#ffffff' }),
@ -65,14 +59,3 @@ export default class DhAppearance extends foundry.abstract.DataModel {
};
}
}
export const DualityRollColor = {
colorful: {
value: 'colorful',
label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.colorful'
},
normal: {
value: 'normal',
label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.normal'
}
};

View file

@ -21,6 +21,13 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
initial: 5,
label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxLoadout.label'
}),
maxDomains: new fields.NumberField({
required: true,
integer: true,
min: 1,
initial: 2,
label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxDomains.label'
}),
traitArray: new fields.ArrayField(new fields.NumberField({ required: true, integer: true }), {
initial: () => [2, 1, 1, 0, 0, -1]
}),

View file

@ -318,8 +318,16 @@ export default class DhpActor extends Actor {
for (var domainCard of domainCards) {
if (levelupAuto) {
const item = await foundry.utils.fromUuid(domainCard.data[0]);
const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]);
const itemData = (await foundry.utils.fromUuid(domainCard.data[0])).toObject();
const embeddedItem = await this.createEmbeddedDocuments('Item', [
{
...itemData,
system: {
...itemData.system,
inVault: true
}
}
]);
selections.push({ ...domainCard, itemUuid: embeddedItem[0].uuid });
} else {
selections.push({ ...domainCard });
@ -329,8 +337,16 @@ export default class DhpActor extends Actor {
const achievementDomainCards = [];
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()]);
const itemData = (await foundry.utils.fromUuid(card.uuid)).toObject();
const embeddedItem = await this.createEmbeddedDocuments('Item', [
{
...itemData,
system: {
...itemData.system,
inVault: true
}
}
]);
card.itemUuid = embeddedItem[0].uuid;
achievementDomainCards.push(card);
}

View file

@ -97,7 +97,7 @@ export const tagifyElement = (element, options, onChange, tagifyOptions = {}) =>
description: option.description
};
}),
maxTags: maxTags,
maxTags: typeof maxTags === 'function' ? maxTags() : maxTags,
dropdown: {
mapValueTo: 'name',
searchKeys: ['name'],

View file

@ -126,4 +126,16 @@
}
}
}
.settings-hint {
width: 100%;
display: flex;
justify-content: end;
label {
width: 240px;
font-style: italic;
text-align: center;
}
}
}

View file

@ -3,7 +3,9 @@
<h1>{{localize 'DAGGERHEART.SETTINGS.Menu.homebrew.name'}}</h1>
</header>
{{formGroup settingFields.schema.fields.maxFear value=settingFields._source.maxFear localize=true}}
{{formGroup settingFields.schema.fields.maxDomains value=settingFields._source.maxDomains localize=true}}
{{formGroup settingFields.schema.fields.maxLoadout value=settingFields._source.maxLoadout localize=true}}
<div class="settings-hint"><label>{{localize "DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxLoadout.hint"}}</label></div>
<h4>{{localize "DAGGERHEART.SETTINGS.Homebrew.FIELDS.traitArray.label"}}</h4>
<div class="trait-array-container">