implements #84 in two distinct ways: left click for a touch friendly dialog, right click for inline editing of a resource.

main
macniel 2026-07-13 21:35:30 +02:00
parent 25152ff8db
commit a42accc7ec
11 changed files with 315 additions and 12 deletions

View File

@ -55,5 +55,19 @@
},
"ITEM_BROWSER": {
"progress": "{current}/{max}: Importiere von {compendium}"
},
"RESOURCE_DIALOG": {
"Lep": {
"title": "Lebenspunkte anpassen"
},
"Aup": {
"title": "Ausdauerpunkte anpassen"
},
"Asp": {
"title": "Astralpunkte anpassen"
},
"Kap": {
"title": "Karmapunkte anpassen"
}
}
}

View File

@ -8,6 +8,20 @@ const {
ArrayField,
} = foundry.data.fields;
/**
*
* @property LE
* @property AU
* @property AE
* @property KE
*/
export const ResourceType = {
LE: "Lep",
AU: "Aup",
AE: "Asp",
KE: "Kap"
}
export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
static defineSchema() {

View File

@ -0,0 +1,113 @@
import {ResourceType} from "../data/character.mjs";
const {
ApplicationV2,
HandlebarsApplicationMixin
} = foundry.applications.api
export class EditResourceDialog extends HandlebarsApplicationMixin(ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ['dsa41', 'dialog', 'resource'],
tag: "form",
position: {
width: 480,
height: 480
},
window: {
resizable: false,
title: "Resource anpassen"
},
form: {
submitOnChange: false,
closeOnSubmit: false,
handler: EditResourceDialog.#onSubmitForm
},
actions: {
setResource: EditResourceDialog.#onSetResource,
}
}
static PARTS = {
form: {
template: 'systems/DSA_4-1/templates/dialog/resource-dialog.hbs',
}
}
_actor = null;
_resourceType = null;
_min = 0;
_current = 0;
_max = 0;
constructor(actor, resourceType, min, current, max) {
super();
this._actor = actor;
this._resourceType = resourceType;
this._min = min;
this._current = current;
this._max = max;
}
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
this.close()
}
static async #onSetResource(event, target) {
const {value} = target.dataset;
switch(this._resourceType) {
case ResourceType.LE:
await this._actor.update({"system.lep.aktuell": value});
break;
case ResourceType.AU:
await this._actor.update({"system.aup.aktuell": value});
break;
case ResourceType.AE:
await this._actor.update({"system.asp.aktuell": value});
break;
case ResourceType.KE:
await this._actor.update({"system.kap.aktuell": value});
}
this.close();
}
async _prepareContext(options) {
const context = await super._prepareContext(options)
context.steps = [];
for (let i = this._min; i <= this._max; ++i ) {
if (i < this._current) {
context.steps.push({
display: i - this._current,
value: i,
isReduction: true,
isIncreasing: false,
});
} else if (i === this._current) {
context.steps.push({
display: i - this._current,
value: i,
isReduction: false,
isIncreasing: false,
});
} else {
context.steps.push({
display: "+" + (i - this._current),
value: i,
isReduction: false,
isIncreasing: true,
});
}
}
return context
}
_configureRenderOptions(options) {
super._configureRenderOptions(options)
if (options.window) {
options.window.title = game.i18n.format("RESOURCE_DIALOG." + this._resourceType + ".title")
}
return options
}
}

View File

@ -24,6 +24,8 @@ import {StandaloneLiturgies} from "./character-standalone/liturgies.mjs";
import {StandaloneHealth} from "./character-standalone/health.mjs";
import {SpellDialog} from "../dialog/spellDialog.mjs";
import {displayRoll} from "../globals/displayRoll.js";
import {ResourceType} from "../data/character.mjs";
import {EditResourceDialog} from "../dialog/resourceDialog.mjs";
const {HandlebarsApplicationMixin, DocumentSheetV2} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
@ -76,7 +78,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
setWounds: CharacterSheet.#setWounds,
switchSet: CharacterSheet.#switchSet,
openInitiative: CharacterSheet.#openInitiative,
editLep: CharacterSheet.#editLep,
editAup: CharacterSheet.#editAup,
editAsp: CharacterSheet.#editAsp,
editKap: CharacterSheet.#editKap,
}
}
@ -272,6 +277,59 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
new SpellDialog(this.document, itemId).render(true)
}
static #editAup(event, target, isRightClicked) {
if (!isRightClicked) {
const min = 0
const current = this.document.system.aup.aktuell
const max = this.document.system.aup.max
const dialog = new EditResourceDialog(this.document, ResourceType.AU, min, current, max)
dialog.render(true)
target.parentElement.querySelector('input').blur();
}
}
static #editLep(event, target, isRightClicked) {
if (!isRightClicked) {
const min = 0
const current = this.document.system.lep.aktuell
const max = this.document.system.lep.max
const dialog = new EditResourceDialog(this.document, ResourceType.LE, min, current, max)
dialog.render(true)
target.parentElement.querySelector('input').blur();
}
}
static #editAsp(event, target, isRightClicked) {
if (!isRightClicked) {
const min = 0
const current = this.document.system.asp.aktuell
const max = this.document.system.asp.max
const dialog = new EditResourceDialog(this.document, ResourceType.AE, min, current, max)
dialog.render(true)
target.parentElement.querySelector('input').blur();
}
}
static #editKap(event, target, isRightClicked) {
if (!isRightClicked) {
const min = 0
const current = this.document.system.kap.aktuell
const max = this.document.system.kap.max
const dialog = new EditResourceDialog(this.document, ResourceType.KE, min, current, max)
dialog.render(true)
target.parentElement.querySelector('input').blur();
}
}
static #startResting(event, target) {
const dialog = new RestingDialog(this.document)
@ -374,6 +432,22 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
if (formData.object["system.lep.aktuell"]?.[1]) {
formData.object["system.lep.aktuell"] = formData.object["system.lep.aktuell"][0]
}
if (formData.object["system.aup.aktuell"]?.[1]) {
formData.object["system.aup.aktuell"] = formData.object["system.aup.aktuell"][0]
}
if (formData.object["system.asp.aktuell"]?.[1]) {
formData.object["system.asp.aktuell"] = formData.object["system.asp.aktuell"][0]
}
if (formData.object["system.kap.aktuell"]?.[1]) {
formData.object["system.kap.aktuell"] = formData.object["system.kap.aktuell"][0]
}
await this.document.update(formData.object)
return false
@ -797,6 +871,17 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
}
}
async _postRender() {
this.element.querySelectorAll('.sidebar-element.resource-bar[data-action]').forEach( e => {
const { action} = e.dataset;
e.addEventListener('contextmenu', (event) => {
if (CharacterSheet.DEFAULT_OPTIONS.actions[action]) {
CharacterSheet.DEFAULT_OPTIONS.actions[action].bind(this)(event, event.target, true);
}
})
})
}
}
export default CharacterSheet

View File

@ -22,6 +22,8 @@ $talent-language-text-color: #000;
$talent-crafting-color: #cd9551;
$talent-crafting-text-color: #000;
$help-fill-color: #60d060ff;
$help-border-color: #308030ff;
$harm-fill-color: #ff0000ff;
$harm-border-color: #3c0000ff;

View File

@ -8,6 +8,8 @@
.resource-bar {
cursor: pointer;
height: 24px;
width: 100%;
position: relative;
@ -16,18 +18,43 @@
margin: 8px 0;
label {
cursor: pointer;
position: absolute;
left: 0;
top: 0;
bottom: 0;
z-index: 3;
width: 40px;
line-height: 24px;
vertical-align: middle;
text-indent: 8px;
color: white;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.3);
}
}
input {
position: absolute;
left: 40px;
top: 0;
width: calc(100% - 40px);
z-index: 4;
height: 22px;
padding: 0;
margin: 0;
line-height: 24px;
vertical-align: middle;
text-indent: 8px;
color: white;
font-size: large;
background: transparent;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.3);
border: 0;
&:hover {
background-color: rgba(0, 0, 0, 0.5);
}
}
span.resource-fill {
position: absolute;
left: 0;

View File

@ -0,0 +1,42 @@
@use "../atoms/colours" as colour;
.dsa41.dialog.resource {
section.steps {
overflow: auto;
flex: 1;
display: grid;
grid-template-columns: repeat(5, 1fr);
.step {
display: inline-block;
border: 1px solid black;
width: 64px;
height: 48px;
line-height: 48px;
vertical-align: middle;
text-align: center;
justify-self: center;
font-weight: bold;
cursor: pointer;
margin: 4px;
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.5),
2px 2px inset rgba(0, 0, 0, 0.2);
&.reducing {
background-color: colour.$harm-fill-color;
border-color: colour.$harm-border-color;
background-blend-mode: hue;
}
&.increasing {
background-color: colour.$help-fill-color;
border-color: colour.$help-border-color;
background-blend-mode: hue;
}
}
}
}

View File

@ -39,4 +39,5 @@
@use "organisms/dialog";
@use "organisms/deity-sheet";
@use "organisms/item-browser-dialog";
@use "organisms/resource-dialog";
@use "atoms/chat";

View File

@ -2,7 +2,7 @@
"id": "DSA_4-1",
"title": "Das Schwarze Auge 4.1",
"description": "Noch ein Spielsystem für Das Schwarze Auge 4.1",
"version": "0.11.2",
"version": "0.0.1",
"compatibility": {
"minimum": 12,
"verified": 13
@ -364,5 +364,5 @@
"primaryTokenAttribute": "lep.aktuell",
"url": "https://git.macniel.online/macniel/foundry-dsa41-game",
"manifest": "https://git.macniel.online/macniel/foundry-dsa41-game/raw/branch/main/src/system.json",
"download": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/0.11.2/release.zip"
"download": "https://git.macniel.online/macniel/foundry-dsa41-game/releases/download/0.0.1/release.zip"
}

View File

@ -31,27 +31,27 @@
<img class="profile-img" src="{{img}}" data-action="editImage" data-edit="img" title="{{name}}"/>
<div class="sidebar-element resource-bar">
<label>LeP: {{this.lepcurrent}}</label><span class="resource-fill lep"
<div class="sidebar-element resource-bar" data-action="editLep">
<label>LeP:</label> <input type="number" name="system.lep.aktuell" value="{{this.system.lep.aktuell}}"/><span class="resource-fill lep"
style="width: {{this.lepper}}%"></span>
</div>
{{#if ausdauer}}
<div class="sidebar-element resource-bar">
<label>AuP: {{this.aupcurrent}}</label><span class="resource-fill aup"
<div class="sidebar-element resource-bar" data-action="editAup">
<label>AuP:</label> <input type="number" name="system.aup.aktuell" value="{{this.system.aup.aktuell}}><span class="resource-fill aup"
style="width: {{this.aupper}}%"></span>
</div>
{{/if}}
{{#if this.hasLiturgies}}
<div class="sidebar-element resource-bar">
<label>KaP: {{this.kapcurrent}}</label><span class="resource-fill kap" style="width: {{this.keper}}%"></span>
<div class="sidebar-element resource-bar" data-action="editKap">
<label>KaP:</label> <input type="number" name="system.kap.aktuell" value="{{this.kapcurrent}}"><span class="resource-fill kap" style="width: {{this.keper}}%"></span>
</div>
{{/if}}
{{#if this.hasSpells}}
<div class="sidebar-element resource-bar">
<label>AsP: {{this.aspcurrent}}</label><span class="resource-fill asp" style="width: {{this.aspper}}%"></span>
<div class="sidebar-element resource-bar" data-action="editAsp">
<label>AsP:</label> <input type="number" name="system.asp.aktuell" value="{{this.aspcurrent}}"><span class="resource-fill asp" style="width: {{this.aspper}}%"></span>
</div>
{{/if}}

View File

@ -0,0 +1,5 @@
<section class="steps">
{{#each steps}}<div class="step{{#if this.isReduction}} reducing{{/if}}{{#if this.isIncreasing}} increasing{{/if}}" data-action="setResource" data-value="{{this.value}}">{{this.display}}</div>{{/each}}
</section>