Added homebrew settings without action handling for now

This commit is contained in:
WBHarry 2025-06-20 01:36:03 +02:00
parent e38ebfab29
commit a65719b314
11 changed files with 478 additions and 5 deletions

View file

@ -297,6 +297,7 @@ const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/views/actionTypes/roll.hbs', 'systems/daggerheart/templates/views/actionTypes/roll.hbs',
'systems/daggerheart/templates/views/actionTypes/cost.hbs', 'systems/daggerheart/templates/views/actionTypes/cost.hbs',
'systems/daggerheart/templates/views/actionTypes/range-target.hbs', 'systems/daggerheart/templates/views/actionTypes/range-target.hbs',
'systems/daggerheart/templates/views/actionTypes/effect.hbs' 'systems/daggerheart/templates/views/actionTypes/effect.hbs',
'systems/daggerheart/templates/settings/components/settings-item-line.hbs'
]); ]);
}; };

View file

@ -87,6 +87,10 @@
} }
}, },
"Homebrew": { "Homebrew": {
"NewDowntimeMove": "Downtime Move",
"DowntimeMoves": "Downtime Moves",
"ResetMovesTitle": "Reset {type} Downtime Moves",
"ResetMovesText": "Are you sure you want to reset?",
"FIELDS": { "FIELDS": {
"maxFear": { "label": "Max Fear" }, "maxFear": { "label": "Max Fear" },
"traitArray": { "label": "Initial Trait Modifiers" } "traitArray": { "label": "Initial Trait Modifiers" }

View file

@ -0,0 +1,144 @@
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhSettingsActionView extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(resolve, reject, title, name, img, description, actions) {
super({});
this.resolve = resolve;
this.reject = reject;
this.viewTitle = title;
this.name = name;
this.img = img;
this.description = description;
this.actions = actions;
}
get title() {
return this.viewTitle;
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'setting', 'dh-style'],
position: { width: '400', height: 'auto' },
actions: {
editImage: this.onEditImage,
addItem: this.addItem,
editItem: this.editItem,
removeItem: this.removeItem,
resetMoves: this.resetMoves,
saveForm: this.saveForm
},
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
};
static PARTS = {
header: { template: 'systems/daggerheart/templates/settings/components/action-view-header.hbs' },
main: {
template: 'systems/daggerheart/templates/settings/components/action-view.hbs'
},
footer: { template: 'systems/daggerheart/templates/settings/components/action-view-footer.hbs' }
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.name = this.name;
context.img = this.img;
context.description = this.description;
context.enrichedDescription = await foundry.applications.ux.TextEditor.enrichHTML(context.description);
context.actions = this.actions;
return context;
}
static async updateData(event, element, formData) {
const { name, img, description } = foundry.utils.expandObject(formData.object);
this.name = name;
this.description = description;
this.render();
}
static async saveForm(event) {
this.resolve({
name: this.name,
img: this.img,
description: this.description,
actions: this.actions
});
this.close(true);
}
static close(fromSave) {
if (!fromSave) {
this.reject();
}
super.close();
}
static onEditImage() {
const fp = new FilePicker({
current: this.img,
type: 'image',
callback: async path => {
this.img = path;
this.render();
},
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
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
});
}
static async addItem() {
const actionType = await this.selectActionType();
const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack,
action = new cls({
_id: foundry.utils.randomID(),
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
});
this.actions.push(action);
this.render();
}
static async editItem(_, button) {
await new DHActionConfig(this.actions[button.dataset.id]).render(true);
}
static removeItem(event, button) {
this.actions = this.actions.filter((_, index) => index !== Number.parseInt(button.dataset.id));
this.render();
}
static resetMoves() {}
}

View file

@ -1,8 +1,9 @@
import { DhHomebrew } from '../../data/settings/_module.mjs'; import { DhHomebrew } from '../../data/settings/_module.mjs';
import DhSettingsActionView from './components/settingsActionsView.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhAutomationSettings extends HandlebarsApplicationMixin(ApplicationV2) { export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) {
constructor() { constructor() {
super({}); super({});
@ -19,7 +20,10 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
classes: ['daggerheart', 'setting', 'dh-style'], classes: ['daggerheart', 'setting', 'dh-style'],
position: { width: '600', height: 'auto' }, position: { width: '600', height: 'auto' },
actions: { actions: {
reset: this.reset, addItem: this.addItem,
editItem: this.editItem,
removeItem: this.removeItem,
resetMoves: this.resetMoves,
save: this.save save: this.save
}, },
form: { handler: this.updateData, submitOnChange: true } form: { handler: this.updateData, submitOnChange: true }
@ -48,8 +52,101 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
this.render(); this.render();
} }
static async reset() { static async addItem(_, target) {
this.settings = new DhHomebrew(); await this.settings.updateSource({
[`restMoves.${target.dataset.type}.moves.${foundry.utils.randomID()}`]: {
name: game.i18n.localize('DAGGERHEART.Settings.Homebrew.NewDowntimeMove'),
img: 'icons/magic/life/cross-worn-green.webp',
description: '',
actions: []
}
});
this.render();
}
static async editItem(_, target) {
const move = this.settings.restMoves[target.dataset.type].moves[target.dataset.id];
new Promise((resolve, reject) => {
new DhSettingsActionView(
resolve,
reject,
game.i18n.localize('DAGGERHEART.Settings.Homebrew.DowntimeMoves'),
move.name,
move.img,
move.description,
move.actions
).render(true);
}).then(data => this.updateAction.bind(this)(data, target.dataset.type, target.dataset.id));
}
async updateAction(data, type, id) {
await this.settings.updateSource({
[`restMoves.${type}.moves.${id}`]: {
name: data.name,
img: data.img,
description: data.description
}
});
this.render();
}
static async removeItem(_, target) {
await this.settings.updateSource({
[`restMoves.${target.dataset.type}.moves.-=${target.dataset.id}`]: null
});
this.render();
}
static async resetMoves(_, target) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
window: {
title: game.i18n.format('DAGGERHEART.Settings.Homebrew.ResetMovesTitle', {
type: game.i18n.localize(
`DAGGERHEART.Downtime.${target.dataset.type === 'shortRest' ? 'ShortRest' : 'LongRest'}.title`
)
})
},
content: game.i18n.localize('DAGGERHEART.Settings.Homebrew.ResetMovesText')
});
if (!confirmed) return;
const fields = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).schema.fields;
const removeUpdate = Object.keys(this.settings.restMoves[target.dataset.type].moves).reduce((acc, key) => {
acc[`-=${key}`] = null;
return acc;
}, {});
const updateBase =
target.dataset.type === 'shortRest'
? fields.restMoves.fields.shortRest.fields
: fields.restMoves.fields.longRest.fields;
const update = {
nrChoices: updateBase.nrChoices.initial,
moves: Object.keys(updateBase.moves.initial).reduce((acc, key) => {
const move = updateBase.moves.initial[key];
acc[key] = {
...move,
name: game.i18n.localize(move.name),
description: game.i18n.localize(move.description)
};
return acc;
}, {})
};
await this.settings.updateSource({
[`restMoves.${target.dataset.type}`]: {
...update,
moves: {
...removeUpdate,
...update.moves
}
}
});
this.render(); this.render();
} }

View file

@ -3178,6 +3178,72 @@ div.daggerheart.views.multiclass {
#resources:has(.fear-bar) { #resources:has(.fear-bar) {
min-width: 200px; min-width: 200px;
} }
.daggerheart.dh-style.setting fieldset.two-columns {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 10px;
}
.daggerheart.dh-style.setting fieldset.two-columns.even {
grid-template-columns: 1fr 1fr;
}
.daggerheart.dh-style.setting .settings-items {
display: flex;
flex-direction: column;
gap: 8px;
}
.daggerheart.dh-style.setting .settings-items .settings-item {
display: flex;
align-items: center;
justify-content: space-between;
border: 1px solid;
border-radius: 8px;
padding: 0 8px 0 0;
}
.daggerheart.dh-style.setting .settings-items .settings-item .settings-sub-item {
display: flex;
align-items: center;
gap: 8px;
}
.daggerheart.dh-style.setting .settings-items .settings-item .settings-sub-item img {
width: 60px;
border-radius: 8px 0 0 8px;
}
.daggerheart.dh-style.setting .settings-items .settings-item .settings-sub-item i {
font-size: 18px;
}
.daggerheart.dh-style.setting .settings-item-header {
display: flex;
align-items: center;
}
.daggerheart.dh-style.setting .settings-item-header .profile {
height: 100px;
width: 100px;
object-fit: cover;
box-sizing: border-box;
cursor: pointer;
}
.daggerheart.dh-style.setting .settings-item-header .item-info {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
text-align: center;
width: 80%;
}
.daggerheart.dh-style.setting .settings-item-header .item-info .item-name input[type='text'] {
font-size: 32px;
height: 42px;
text-align: center;
width: 90%;
transition: all 0.3s ease;
outline: 2px solid transparent;
border: 1px solid transparent;
}
.daggerheart.dh-style.setting .settings-item-header .item-info .item-name input[type='text']:hover[type='text'],
.daggerheart.dh-style.setting .settings-item-header .item-info .item-name input[type='text']:focus[type='text'] {
box-shadow: none;
outline: 2px solid light-dark(#18162e, #f3c267);
}
.daggerheart.dh-style.setting .settings-col { .daggerheart.dh-style.setting .settings-col {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -1,4 +1,84 @@
.daggerheart.dh-style.setting { .daggerheart.dh-style.setting {
fieldset {
&.two-columns {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 10px;
&.even {
grid-template-columns: 1fr 1fr;
}
}
}
.settings-items {
display: flex;
flex-direction: column;
gap: 8px;
.settings-item {
display: flex;
align-items: center;
justify-content: space-between;
border: 1px solid;
border-radius: 8px;
padding: 0 8px 0 0;
.settings-sub-item {
display: flex;
align-items: center;
gap: 8px;
img {
width: 60px;
border-radius: 8px 0 0 8px;
}
i {
font-size: 18px;
}
}
}
}
.settings-item-header {
display: flex;
align-items: center;
.profile {
height: 100px;
width: 100px;
object-fit: cover;
box-sizing: border-box;
cursor: pointer;
}
.item-info {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
text-align: center;
width: 80%;
.item-name input[type='text'] {
font-size: 32px;
height: 42px;
text-align: center;
width: 90%;
transition: all 0.3s ease;
outline: 2px solid transparent;
border: 1px solid transparent;
&:hover[type='text'],
&:focus[type='text'] {
box-shadow: none;
outline: 2px solid light-dark(@dark-blue, @golden);
}
}
}
}
.settings-col { .settings-col {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -0,0 +1,3 @@
<section class='tab-form-footer'>
<button data-action="saveForm"><i class="fa-solid fa-floppy-disk"></i> {{localize "Save"}}</button>
</section>

View file

@ -0,0 +1,6 @@
<header class='settings-item-header'>
<img class='profile' src='{{this.img}}' data-action='editImage' data-edit='img' />
<div class='item-info'>
<h1 class='item-name'><input type='text' name='name' value='{{this.name}}' /></h1>
</div>
</header>

View file

@ -0,0 +1,18 @@
<div>
<fieldset>
<legend>{{localize "Description"}}</legend>
<prose-mirror name="description" value="{{description}}" toggled=true>
{{{ enrichedDescription }}}
</prose-mirror>
</fieldset>
{{!-- <fieldset>
<legend>{{localize "Actions"}} <a data-action="addItem"><i class="fa-solid fa-plus"></i></a></legend>
<div class="settings-items">
{{#each this.actions as |action index|}}
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" action type="actions" id=index }}
{{/each}}
</div>
</fieldset> --}}
</div>

View file

@ -0,0 +1,22 @@
<div class="settings-item">
<div class="settings-sub-item">
<img src="{{this.img}}" />
<div>{{this.name}}</div>
</div>
<div class="settings-sub-item">
<a
data-action="editItem"
data-type="{{this.type}}"
data-id="{{this.id}}"
>
<i class="fa-solid fa-globe"></i>
</a>
<a
data-action="removeItem"
data-type="{{this.type}}"
data-id="{{this.id}}"
>
<i class='fas fa-trash'></i>
</a>
</div>
</div>

View file

@ -10,6 +10,38 @@
</div> </div>
{{/each}} {{/each}}
</div> </div>
<fieldset class="two-columns even">
<legend>{{localize "DAGGERHEART.Settings.Homebrew.DowntimeMoves"}}</legend>
<fieldset>
<legend>
{{localize "DAGGERHEART.Downtime.LongRest.title"}}
<a data-action="addItem" data-type="longRest"><i class="fa-solid fa-plus"></i></a>
<a data-action="resetMoves" data-type="longRest"><i class="fa-solid fa-arrow-rotate-left"></i></a>
</legend>
<div class="settings-items">
{{#each settingFields._source.restMoves.longRest.moves as |move id|}}
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" this type="longRest" id=id }}
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>
{{localize "DAGGERHEART.Downtime.ShortRest.title"}}
<a data-action="addItem" data-type="shortRest"><i class="fa-solid fa-plus"></i></a>
<a data-action="resetMoves" data-type="shortRest"><i class="fa-solid fa-arrow-rotate-left"></i></a>
</legend>
<div class="settings-items">
{{#each settingFields._source.restMoves.shortRest.moves as |move id|}}
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" this type="shortRest" id=id }}
{{/each}}
</div>
</fieldset>
</fieldset>
<footer class="form-footer"> <footer class="form-footer">
<button data-action="reset"> <button data-action="reset">