Talents can now be added or replaced via drag and drop
parent
35271b8c83
commit
073c25e89a
13
src/main.mjs
13
src/main.mjs
|
|
@ -5,15 +5,16 @@ import { CharacterSheet } from "./module/sheets/characterSheet.mjs";
|
|||
import {SkillDataModel} from "./module/data/skill.mjs";
|
||||
import {SpellDataModel} from "./module/data/spell.mjs";
|
||||
import {Character} from "./module/documents/character.mjs";
|
||||
import {DragDropDSA41} from "./module/extensions/DragDropDSA41.mjs";
|
||||
|
||||
async function preloadHandlebarsTemplates() {
|
||||
return loadTemplates([
|
||||
// ui partials.
|
||||
'systems/DSA_4-1/templates/ui/partial-rollable-button.hbs',
|
||||
'systems/DSA_4-1/templates/ui/partial-attribute-button.hbs'
|
||||
'systems/DSA_4-1/templates/ui/partial-attribute-button.hbs',
|
||||
'systems/DSA_4-1/templates/ui/partial-talent-editable.hbs'
|
||||
]);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Hooks.once("init", () => {
|
||||
|
||||
|
|
@ -30,6 +31,8 @@ Hooks.once("init", () => {
|
|||
spell: SpellDataModel
|
||||
}
|
||||
|
||||
CONFIG.ux.DragDrop = DragDropDSA41;
|
||||
|
||||
console.log("DSA 4.1 is ready for development!")
|
||||
|
||||
Actors.registerSheet('dsa41.character', CharacterSheet, {
|
||||
|
|
@ -52,3 +55,7 @@ Hooks.once("init", () => {
|
|||
|
||||
return preloadHandlebarsTemplates();
|
||||
})
|
||||
|
||||
Hooks.on('dropActorSheetData', (actor, sheet, data) => {
|
||||
CharacterSheet.onDroppedData(actor, sheet, data);
|
||||
} )
|
||||
|
|
@ -53,7 +53,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
|
|||
super._initialize(options);
|
||||
}
|
||||
|
||||
_onCreate(data, options, userId) {
|
||||
async _onCreate(data, options, userId) {
|
||||
// prepare base talents
|
||||
const talentsByName = [
|
||||
"Athletik", "Klettern", "Körperbeherrschung", "Schleichen", "Schwimmen", "Selbstbeherrschung", "Sich Verstecken", "Singen", "Sinnenschärfe", "Tanzen", "Zechen",
|
||||
|
|
@ -79,7 +79,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
|
|||
})
|
||||
|
||||
// push base talents
|
||||
game.actors.getName(data.name).update({system: {talente}})
|
||||
await game.actors.getName(data.name).update({system: {talente}})
|
||||
|
||||
const startEigenschaften = {
|
||||
"mu": 10,
|
||||
|
|
@ -92,7 +92,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
|
|||
"kk": 10,
|
||||
}
|
||||
|
||||
game.actors.getName(data.name).update({system: {attribute: startEigenschaften}})
|
||||
await game.actors.getName(data.name).update({system: {attribute: startEigenschaften}})
|
||||
super._onCreate(data, options, userId);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,4 +24,9 @@ export class Character extends Actor {
|
|||
}
|
||||
|
||||
|
||||
static onDroppedData(character, characterSheet, uuid) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import {DragDropDSA41} from "./DragDropDSA41.mjs";
|
||||
|
||||
export default function DragDropApplicationMixin(Base) {
|
||||
return class DragDropApplication extends Base {
|
||||
/** @override */
|
||||
_onDragOver(event) {
|
||||
const data = DragDropDSA41.getPayload(event);
|
||||
DragDropDSA41.dropEffect = event.dataTransfer.dropEffect = (foundry.utils.getType(data) === "Object")
|
||||
? this._dropBehavior(event, data) : "copy";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The behavior for the dropped data. When called during the drop event, ensure this is called before awaiting
|
||||
* anything or the drop behavior will be lost.
|
||||
* @param {DragEvent} event The drag event.
|
||||
* @param {object} [data] The drag payload.
|
||||
* @returns {DropEffectValue}
|
||||
*/
|
||||
_dropBehavior(event, data) {
|
||||
data ??= DragDropDSA41.getPayload(event);
|
||||
const allowed = this._allowedDropBehaviors(event, data);
|
||||
let behavior = DragDropDSA41.dropEffect ?? event.dataTransfer?.dropEffect;
|
||||
|
||||
if ( event.type === "dragover" ) {
|
||||
if ( areKeysPressed(event, "dragMove") ) behavior = "move";
|
||||
else if ( areKeysPressed(event, "dragCopy") ) behavior = "copy";
|
||||
else behavior = this._defaultDropBehavior(event, data);
|
||||
}
|
||||
|
||||
if ( (behavior !== "none") && !allowed.has(behavior) ) return allowed.first() ?? "none";
|
||||
return behavior || "copy";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Types of allowed drop behaviors based on the origin & target of a drag event.
|
||||
* @param {DragEvent} event The drag event.
|
||||
* @param {object} [data] The drag payload.
|
||||
* @returns {Set<DropEffectValue>}
|
||||
* @protected
|
||||
*/
|
||||
_allowedDropBehaviors(event, data) {
|
||||
return new Set();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Determine the default drop behavior for the provided operation.
|
||||
* @param {DragEvent} event The drag event.
|
||||
* @param {object} [data] The drag payload.
|
||||
* @returns {DropEffectValue}
|
||||
* @protected
|
||||
*/
|
||||
_defaultDropBehavior(event, data) {
|
||||
return "copy";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
export class DragDropDSA41 extends foundry.applications.ux.DragDrop {
|
||||
|
||||
/**
|
||||
* Drop effect used for current drag operation.
|
||||
* @type {DropEffectValue|null}
|
||||
*/
|
||||
static dropEffect = null;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Stored drag event payload.
|
||||
* @type {{ data: any, event: DragEvent }|null}
|
||||
*/
|
||||
static #payload = null;
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _handleDragStart(event) {
|
||||
await this.callback(event, "dragstart");
|
||||
if ( event.dataTransfer.items.length ) {
|
||||
console.log(event)
|
||||
event.stopPropagation();
|
||||
let data = event.dataTransfer.getData("application/json") || event.dataTransfer.getData("text/plain");
|
||||
try { data = JSON.parse(data); } catch(err) {}
|
||||
DragDropDSA41.#payload = data ? { event, data } : null;
|
||||
} else {
|
||||
DragDropDSA41.#payload = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _handleDragEnd(event) {
|
||||
await this.callback(event, "dragend");
|
||||
DragDropDSA41.dropEffect = null;
|
||||
DragDropDSA41.#payload = null;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the data payload for the current drag event.
|
||||
* @param {DragEvent} event
|
||||
* @returns {any}
|
||||
*/
|
||||
static getPayload(event) {
|
||||
if ( !DragDropDSA41.#payload?.data ) return null;
|
||||
return DragDropDSA41.#payload.data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
import {DragDropDSA41} from "../extensions/DragDropDSA41.mjs";
|
||||
|
||||
export class CharacterSheet extends ActorSheet {
|
||||
/**@override */
|
||||
static get defaultOptions() {
|
||||
|
|
@ -34,6 +36,7 @@ export class CharacterSheet extends ActorSheet {
|
|||
// Add the actor's data to context.data for easier access, as well as flags.
|
||||
context.system = actorData.system;
|
||||
context.flags = actorData.flags;
|
||||
context.isEditable = actorData.editable;
|
||||
context.attributes = [
|
||||
{
|
||||
eigenschaft: "mu",
|
||||
|
|
@ -85,11 +88,14 @@ export class CharacterSheet extends ActorSheet {
|
|||
|
||||
];
|
||||
context.skills = {};
|
||||
context.flatSkills = [];
|
||||
|
||||
if ( context.system.talente?.length >= 0) {
|
||||
context.system.talente.forEach(talent => {
|
||||
context.system.talente.forEach( (talent, index) => {
|
||||
if (talent.talent) {
|
||||
const taw = talent.taw;
|
||||
console.log(taw);
|
||||
const talentObjekt = game.items.get(talent.talent);
|
||||
console.log(talent);
|
||||
const talentGruppe = talentObjekt.system.gruppe;
|
||||
const eigenschaften = Object.values(talentObjekt.system.probe);
|
||||
const werte = [
|
||||
|
|
@ -102,20 +108,25 @@ export class CharacterSheet extends ActorSheet {
|
|||
context.skills[talentGruppe] = [];
|
||||
}
|
||||
|
||||
context.skills[talentGruppe].push({
|
||||
const obj = {
|
||||
type: "talent",
|
||||
gruppe: talentGruppe,
|
||||
name: talentObjekt.name,
|
||||
taw: "" + taw,
|
||||
tawPath: `system.talente.${index}.taw`,
|
||||
werte,
|
||||
rollEigenschaft1: werte[0].value,
|
||||
rollEigenschaft2: werte[1].value,
|
||||
rollEigenschaft3: werte[2].value,
|
||||
probe: `(${eigenschaften.join("/")})`
|
||||
});
|
||||
};
|
||||
|
||||
context.skills[talentGruppe].push(obj);
|
||||
context.flatSkills.push(obj);
|
||||
}
|
||||
})
|
||||
}
|
||||
console.log(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -215,4 +226,73 @@ export class CharacterSheet extends ActorSheet {
|
|||
|
||||
}
|
||||
|
||||
static onDroppedData(actor, characterSheet, data) {
|
||||
const item = game.items.get(foundry.utils.parseUuid(data.uuid).id)
|
||||
console.log();
|
||||
let alreadyInSet = false;
|
||||
let previousTaw = 0;
|
||||
actor.system.talente.forEach(({taw, talent}) => {
|
||||
if (talent._id === item._id) {
|
||||
alreadyInSet = talent;
|
||||
previousTaw = taw;
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
const myContent = `
|
||||
TaW:
|
||||
<input id="taw" type="number" value="${previousTaw}" />
|
||||
`;
|
||||
new Dialog({
|
||||
title: `Talent ${item.name} ${alreadyInSet?'ersetzen':'hinzufügen'}`,
|
||||
content: myContent,
|
||||
buttons: {
|
||||
button1: {
|
||||
label: "hinzufügen",
|
||||
callback: (html) => myCallback(html),
|
||||
icon: `<i class="fas fa-check"></i>`
|
||||
}
|
||||
}
|
||||
}).render(true);
|
||||
|
||||
async function myCallback(html) {
|
||||
const taw = html.find("input#taw").val();
|
||||
|
||||
let index = actor.system.talente.findIndex( predicate => predicate.talent._id === alreadyInSet._id )
|
||||
let sorted = [];
|
||||
if (alreadyInSet) {
|
||||
actor.system.talente[index].taw = taw;
|
||||
sorted = actor.system.talente;
|
||||
|
||||
} else {
|
||||
sorted = [{
|
||||
taw: taw,
|
||||
talent: {_id: item._id, name: item.name}
|
||||
}, ...actor.system.talente].sort((a, b) => a.talent.name.localeCompare(b.talent.name));
|
||||
}
|
||||
|
||||
const serialised = sorted.map(({taw, talent}) => {
|
||||
return {
|
||||
taw: taw,
|
||||
talent: talent._id
|
||||
}
|
||||
});
|
||||
|
||||
await actor.update({
|
||||
system: {
|
||||
talente: [
|
||||
|
||||
...serialised
|
||||
]
|
||||
}
|
||||
});
|
||||
await characterSheet.render(true);
|
||||
ui.notifications.info(`Talent ${item.name} auf TaW ${taw} hinzugefügt`);
|
||||
|
||||
}
|
||||
|
||||
actor.items.clear()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
export class SkillSheet extends foundry.appv1.sheets.ItemSheet {
|
||||
import {DragDropDSA41} from "../extensions/DragDropDSA41.mjs";
|
||||
import DragDropApplicationMixin from "../extensions/DragDropApplicationMixin.mjs";
|
||||
|
||||
export class SkillSheet extends DragDropApplicationMixin(foundry.appv1.sheets.ItemSheet) {
|
||||
/**@override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
|
|
@ -35,13 +38,14 @@ export class SkillSheet extends foundry.appv1.sheets.ItemSheet {
|
|||
context.system = skillData.system;
|
||||
context.flags = skillData.flags;
|
||||
context.categoryOptions = {
|
||||
kampf: "Kampf",
|
||||
körperlich: "Körperlich",
|
||||
gesellschaft: "Gesellschaft",
|
||||
natur: "Natur",
|
||||
wissen: "Wissen",
|
||||
sprachen: "Sprache und Schriften",
|
||||
handwerk: "Handwerk"
|
||||
Kampf: "Kampf",
|
||||
Körperlich: "Körperlich",
|
||||
Gesellschaft: "Gesellschaft",
|
||||
Natur: "Natur",
|
||||
Wissen: "Wissen",
|
||||
Sprachen: "Sprache",
|
||||
Schriften: "Schriften",
|
||||
Handwerk: "Handwerk"
|
||||
}
|
||||
|
||||
return context;
|
||||
|
|
@ -52,6 +56,60 @@ export class SkillSheet extends foundry.appv1.sheets.ItemSheet {
|
|||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.isEditable) return;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Drag & Drop */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_allowedDropBehaviors(event, data) {
|
||||
console.log(data, event);
|
||||
if ( !data?.uuid ) return new Set(["copy", "link"]);
|
||||
const allowed = new Set(["copy", "move", "link"]);
|
||||
const s = foundry.utils.parseUuid(data.uuid);
|
||||
const t = foundry.utils.parseUuid(this.document.uuid);
|
||||
const sCompendium = s.collection instanceof foundry.documents.collections.CompendiumCollection;
|
||||
const tCompendium = t.collection instanceof foundry.documents.collections.CompendiumCollection;
|
||||
|
||||
// If either source or target are within a compendium, but not inside the same compendium, move not allowed
|
||||
if ( (sCompendium || tCompendium) && (s.collection !== t.collection) ) allowed.delete("move");
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
_defaultDropBehavior(event, data) {
|
||||
if ( !data?.uuid ) return "copy";
|
||||
const d = foundry.utils.parseUuid(data.uuid);
|
||||
const t = foundry.utils.parseUuid(this.document.uuid);
|
||||
const base = d.embedded?.length ? "document" : "primary";
|
||||
console.log(d, t, base);
|
||||
return (d.collection === t.collection) && (d[`${base}Id`] === t[`${base}Id`])
|
||||
&& (d[`${base}Type`] === t[`${base}Type`]) ? "move" : "copy";
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
async _onDragStart(event) {
|
||||
await super._onDragStart(event);
|
||||
if ( !this.document.isOwner || this.document.collection?.locked ) {
|
||||
event.dataTransfer.effectAllowed = "copyLink";
|
||||
}
|
||||
}
|
||||
|
||||
_onDragOver(event) {
|
||||
super._onDragOver(event);
|
||||
console.log(event);
|
||||
}
|
||||
|
||||
_dropBehavior(event, data) {
|
||||
console.log(event, data);
|
||||
return super._dropBehavior(event, data);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,13 +72,14 @@ $rollable_colours: (
|
|||
position: absolute;
|
||||
right: 0;
|
||||
height: 32px;
|
||||
top: 0;
|
||||
|
||||
.eigenschaft {
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
position: relative;
|
||||
top: -32px;
|
||||
top: 0;
|
||||
|
||||
span.name {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@
|
|||
<header class="sheet-header">
|
||||
{{!-- Header stuff goes here --}}
|
||||
<div class="header-fields">
|
||||
<div class="editlock">
|
||||
<label>
|
||||
<input type="checkbox" name="isEditable" {{checked isEditable}}/>
|
||||
<span>Editieren</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="attribute">
|
||||
{{#each attributes}}
|
||||
{{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}}
|
||||
|
|
@ -40,6 +46,14 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="tab skills" data-group="primary" data-tab="skills">
|
||||
{{#if this.isEditable}}
|
||||
<h2>Talentwerte</h2>
|
||||
<ul>
|
||||
{{#each flatSkills}}
|
||||
<li>{{> "systems/DSA_4-1/templates/ui/partial-talent-editable.hbs" this}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<h2>Körperliche Talente</h2>
|
||||
<ul>
|
||||
<li>
|
||||
|
|
@ -99,6 +113,7 @@
|
|||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
</form>
|
||||
|
|
@ -18,8 +18,8 @@
|
|||
<div class="tab meta" data-group="primary" data-tab="meta">
|
||||
<div>
|
||||
<label>Kategorie
|
||||
<select type="text" name="system.gruppe.value">
|
||||
{{selectOptions categoryOptions selected=value}}
|
||||
<select name="system.gruppe">
|
||||
{{selectOptions categoryOptions selected=system.gruppe inverted=true}}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
|
@ -58,9 +58,15 @@
|
|||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>Voraussetzung
|
||||
<input type="text" name="system.vorraussetzung" value="{{system.voraussetzung}}" />
|
||||
</label>
|
||||
<label>Voraussetzung</label>
|
||||
<ul>
|
||||
{{#each system.voraussetzung as |pair key|}}
|
||||
<li>
|
||||
<input type="text" name="system.vorraussetzung.{{key}}.wert" value="{{pair.wert}}" />
|
||||
<input type="text" name="system.vorraussetzung.{{key}}.talent" value="{{pair.talent}}" />
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<div class="block rollable {{this.type}}">
|
||||
|
||||
<div class="die">
|
||||
<svg viewBox="0 0 6.3499998 6.35">
|
||||
<g
|
||||
id="g54292"
|
||||
transform="matrix(0.18024007,0,0,0.18024007,-0.89816307,-0.85756211)"
|
||||
style="stroke-width:1.05833;stroke-dasharray:none">
|
||||
<path
|
||||
style="stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="M 22.60018,5.4074448 15.210951,18.121927 7.821723,13.87057 Z"
|
||||
id="path54272"
|
||||
class="die topleft" />
|
||||
<path
|
||||
style="stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="M 22.60018,5.4074448 29.989407,18.121927 37.34771,13.890365 Z"
|
||||
id="path54274"
|
||||
class="die topright" />
|
||||
<path
|
||||
style="stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="m 29.989407,18.121927 7.389229,12.754072 -2e-6,-17.005429 z"
|
||||
id="path54276"
|
||||
class="die bottomright" />
|
||||
<path
|
||||
style="display:inline;stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="m 15.210951,18.121927 -7.3934235,12.756367 2e-6,-17.005429 z"
|
||||
id="path54278"
|
||||
class="die bottomleft" />
|
||||
<path
|
||||
style="display:inline;stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="M 7.8175275,30.878293 22.600179,39.378712 37.378634,30.875999 Z"
|
||||
id="path54280"
|
||||
class="die bottom" />
|
||||
<path
|
||||
style="display:inline;stroke:#000000;stroke-width:1.05833;stroke-linejoin:bevel;stroke-dasharray:none"
|
||||
d="M 7.821723,30.875999 22.600179,5.3678558 37.378634,30.875999 Z"
|
||||
id="path54282"
|
||||
class="die center" />
|
||||
<path
|
||||
style="fill-opacity:1;stroke:#000000;stroke-width:0.896643;stroke-dasharray:none;paint-order:normal"
|
||||
id="path2181"
|
||||
class="die border"
|
||||
d="m 35.923409,110.09622 -12.498871,7.21622 -12.498871,-7.21622 V 95.663763 l 12.498871,-7.216227 12.498871,7.216227 z"
|
||||
transform="matrix(1.1823833,0,0,1.1782771,-5.0966027,-98.847851)" />
|
||||
</g>
|
||||
</svg>
|
||||
<span class="value">
|
||||
</span>
|
||||
</div>
|
||||
<div class="container">
|
||||
<span class="name">{{this.name}}</span>
|
||||
<label class="taw"><span>TAW: </span>
|
||||
<input type="text" name="{{this.tawPath}}.value" value="{{this.taw}}" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
Reference in New Issue