implements creating Equipment from scratch and also an Equipment/Item Browser from where to drag and drop (perhaps even buy from) new Equipment onto an Actor.

pull/65/head
macniel 2025-11-12 00:21:55 +01:00
parent ed893f6b9d
commit c2b8a7d895
7 changed files with 258 additions and 1 deletions

View File

@ -0,0 +1,132 @@
import {Equipment} from "../documents/equipment.mjs";
const {
ApplicationV2,
HandlebarsApplicationMixin
} = foundry.applications.api
export class ItemBrowserDialog extends HandlebarsApplicationMixin(ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ['dsa41', 'dialog', 'item-browser'],
tag: "form",
position: {
width: 640,
height: 480
},
window: {
resizable: true,
},
actions: {
buy: ItemBrowserDialog.#buy
}
}
static PARTS = {
form: {
template: 'systems/DSA_4-1/templates/dialog/item-browser-dialog.hbs',
}
}
/**
* @type {Actor}
* @private
*/
_actor = null
/**
*
* @type {[Equipment]}
* @private
*/
_items = []
constructor(actor) {
super();
this._actor = actor
// load compendium data
this._items = []
}
static async #buy(event, target) {
}
_canDragDrop(event, options) {
return game.user.isGM
}
_canDrag(event, options) {
return true
}
/**
* An event that occurs when a drag workflow begins for a draggable item on the sheet.
* @param {DragEvent} event The initiating drag start event
* @returns {Promise<void>}
* @protected
*/
async _onDragStart(event) {
const target = event.currentTarget;
let dragData;
if (target.dataset.itemId) {
dragData = {
type: "Item",
uuid: target.dataset.itemId
}
}
// Set data transfer
if (!dragData) return;
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
}
async _prepareContext(options) {
const context = await super._prepareContext(options)
context.items = this._items
return context
}
async _onRender(context, options) {
if (this._items.length === 0) {
const compendia = [
game.packs.get('DSA_4-1.Armor'),
game.packs.get('DSA_4-1.Weapons'),
game.packs.get('DSA_4-1.Ammunition'),
game.packs.get('DSA_4-1.Items')
]
for (const c of compendia) {
const it = await c.getDocuments()
it.forEach((item) => {
const uuid = item.uuid
const e = new Equipment(item)
this._items.push({
img: item.img,
uuid,
type: item.type,
name: item.name,
price: e.system.price,
weight: e.system.weight,
category: e.system.category.join(", ")
})
console.log("importing ", item.name)
})
console.log("done importing from ", c)
}
this.render({parts: ["form"]})
}
new foundry.applications.ux.DragDrop.implementation({
dropSelector: ".window-content",
dragSelector: ".item",
permissions: {
drag: this._canDrag.bind(this)
},
callbacks: {
dragstart: this._onDragStart.bind(this),
}
}).bind(this.element)
}
}

View File

@ -20,6 +20,7 @@ import {Talent} from "../data/talent.mjs";
import {Character} from "../documents/character.mjs";
import {currency} from "../handlebar-helpers/currency.mjs";
import {DeityDataModel} from "../data/deity.mjs";
import {ItemBrowserDialog} from "../dialog/itemBrowserDialog.mjs";
function initGlobalAccess() {
@ -30,6 +31,7 @@ function initGlobalAccess() {
Wunde,
RestingDialog,
BattleDialog,
ItemBrowserDialog,
Talent,
displayCurrency: currency
}

View File

@ -14,6 +14,8 @@ import {RestingDialog} from "../dialog/restingDialog.mjs";
import {LiturgyDialog} from "../dialog/liturgyDialog.mjs";
import {TalentDialog} from "../dialog/talentDialog.mjs";
import {AttributeDialog} from "../dialog/attributeDialog.mjs";
import {ItemBrowserDialog} from "../dialog/itemBrowserDialog.mjs";
import * as EquipmentDocument from "../documents/equipment.mjs";
const {HandlebarsApplicationMixin, DocumentSheetV2} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
@ -51,6 +53,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
rest: CharacterSheet.#startResting,
removeEffect: CharacterSheet.#removeEffect,
rollDamage: CharacterSheet.#rollDamage,
openItemBrowser: CharacterSheet.#openItemBrowser,
newItem: CharacterSheet.#addNewItem
}
}
@ -250,6 +254,19 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
}
static async #openItemBrowser(event, target) {
new ItemBrowserDialog(this.document).render(true)
}
static async #addNewItem(event, target) {
let item = new EquipmentDocument.Equipment({
name: "Neuer Gegenstand",
type: "Equipment",
})
const items = await this.document.createEmbeddedDocuments("Item", [item])
items[0].sheet.render(true)
}
_configureRenderOptions(options) {
super._configureRenderOptions(options)

View File

@ -0,0 +1,57 @@
.dsa41.dialog.item-browser {
.window-content [data-application-part] {
display: grid;
grid-template-columns: 240px 1fr;
height: 100%;
gap: 16px;
aside {
width: 240px;
}
.scrollable-table {
display: grid;
grid-template-rows: 32px 1fr;
overflow: hidden;
.header {
display: grid;
grid-template-columns: 64px 1fr 120px 120px 120px;
gap: 4px;
background-color: rgba(0, 0, 0, 0.3);
* {
font-weight: bold;
line-height: 32px;
vertical-align: middle;
}
}
.scroll-y {
overflow-x: hidden;
overflow-y: auto;
border: 1px inset #ccc;
.item {
display: grid;
grid-template-columns: 64px 1fr 120px 120px 120px;
gap: 4px;
&:nth-child(odd) {
background-color: rgba(0, 0, 0, 0.1);
}
}
}
}
}
}

View File

@ -36,3 +36,4 @@
@use "organisms/liturgy-sheet";
@use "organisms/dialog";
@use "organisms/deity-sheet";
@use "organisms/item-browser-dialog";

View File

@ -16,6 +16,8 @@
<h3 class="inventory-header">Inventar </h3>
<button data-action="newItem"><i class="fa-solid fa-sack" data-tooltip="Neuer Gegenstand"></i></button>
<button data-action="openItemBrowser"><i class="fa-solid fa-store" data-tooltip="Einkaufen"></i></button>
<div class="inventory">
{{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}}
</div>

View File

@ -0,0 +1,46 @@
<div>
<aside>
<fieldset>
<legend>Name</legend>
<input name="filter_name" type="text">
</fieldset>
<fieldset>
<legend>Kategorie</legend>
<select name="filter_category">
</select>
</fieldset>
<fieldset>
<legend>Preis</legend>
<input name="filter_price" type="range" min="{{minimumPrice}}" max="{{maximumPrice}}"/>
</fieldset>
<fieldset>
<legend>Gewicht</legend>
<input name="filter_weight" type="range" min="{{minimumWeight}}" max="{{maximumWeight}}"/>
</fieldset>
</aside>
<div class="scrollable-table">
<div class="header">
<span></span>
<span>Name</span>
<span>Kategorie</span>
<span>Preis</span>
<span>Gewicht</span>
</div>
<div class="scroll-y items">
{{#each items}}
<div class="item" data-item-id="{{this.uuid}}" draggable="true">
<img class="image" src="{{this.img}}" alt="{{this.name}}"/>
<span class="name">{{this.name}}</span>
<span class="category">{{this.category}}</span>
<span class="price">{{currency this.price}}</span>
<span class="weight">{{weight this.weight}}</span>
</div>
{{/each}}
</div>
</div>
</div>