Sortierbare Items (#68)

Changes:
 + Items sind jetzt sortierbar
 + Items können jetzt auf andere Actor übertragen werden
 + Löschen button für Mods
Reviewed-on: #68
This commit is contained in:
Byroks 2024-03-04 10:01:47 +01:00
parent bb9d20f586
commit e465bac5ef
9 changed files with 260 additions and 268 deletions

View File

@ -1,5 +1,18 @@
import { M5Item } from "../items/M5Item"; import { M5Item } from "../items/M5Item";
import { M5Attribute, M5CharacterCalculatedData, M5ItemMod, M5ItemType, M5ModOperation, M5ModResult, M5ModType, M5RollData, M5Skill, M5SkillCalculated, M5SkillLearned, M5SkillType } from "../M5Base"; import {
M5Attribute,
M5CharacterCalculatedData,
M5ItemMod,
M5ItemType,
M5ModOperation,
M5ModResult,
M5ModType,
M5RollData,
M5Skill,
M5SkillCalculated,
M5SkillLearned,
M5SkillType,
} from "../M5Base";
import M5ModAggregate from "./M5ModAggregate"; import M5ModAggregate from "./M5ModAggregate";
export class M5Character extends Actor { export class M5Character extends Actor {
// constructor( // constructor(
@ -226,6 +239,7 @@ export class M5Character extends Actor {
if (!skip?.containers) { if (!skip?.containers) {
context.items context.items
?.filter((item) => item.type === "container") ?.filter((item) => item.type === "container")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -263,6 +277,7 @@ export class M5Character extends Actor {
if (!skip?.items) { if (!skip?.items) {
context.items context.items
?.filter((item) => item.type === "item") ?.filter((item) => item.type === "item")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -280,10 +295,10 @@ export class M5Character extends Actor {
if (!!item.system.containerId) { if (!!item.system.containerId) {
ret.gear.containers[item.system.containerId].weight += parseFloat((item.system.weight * item.system.quantity).toPrecision(4)); ret.gear.containers[item.system.containerId].weight += parseFloat((item.system.weight * item.system.quantity).toPrecision(4));
if (ret.gear.containers[item.system.containerId].equipped) { if (ret.gear.containers[item.system.containerId].equipped) {
ret.stats.encumbrance += (item.system.weight * item.system.quantity); ret.stats.encumbrance += item.system.weight * item.system.quantity;
} }
} else if (item.system.equipped) { } else if (item.system.equipped) {
ret.stats.encumbrance += (item.system.weight * item.system.quantity); ret.stats.encumbrance += item.system.weight * item.system.quantity;
} }
let icon = item.img; let icon = item.img;
@ -316,6 +331,7 @@ export class M5Character extends Actor {
context.items context.items
?.filter((item) => item.type === "weapon") ?.filter((item) => item.type === "weapon")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -364,6 +380,7 @@ export class M5Character extends Actor {
context.items context.items
?.filter((item) => item.type === "defensiveWeapon") ?.filter((item) => item.type === "defensiveWeapon")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -404,6 +421,7 @@ export class M5Character extends Actor {
context.items context.items
?.filter((item) => item.type === "armor") ?.filter((item) => item.type === "armor")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -474,7 +492,7 @@ export class M5Character extends Actor {
if (item.length === 0) { if (item.length === 0) {
let messageContent = `Höchstlast wurde überschritten: 1 AP Schaden durch Belastung alle 10 Minuten abziehen!`; let messageContent = `Höchstlast wurde überschritten: 1 AP Schaden durch Belastung alle 10 Minuten abziehen!`;
let chatData = { let chatData = {
speaker: ChatMessage.getSpeaker({actor: Actor.name}), speaker: ChatMessage.getSpeaker({ actor: Actor.name }),
content: messageContent, content: messageContent,
}; };
ChatMessage.create(chatData, {}); ChatMessage.create(chatData, {});
@ -500,6 +518,7 @@ export class M5Character extends Actor {
if (!skip?.effects) { if (!skip?.effects) {
context.items context.items
?.filter((item) => item.type === "effect") ?.filter((item) => item.type === "effect")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -521,6 +540,7 @@ export class M5Character extends Actor {
if (!skip?.skills) { if (!skip?.skills) {
context.items context.items
?.filter((item) => item.type === "skill") ?.filter((item) => item.type === "skill")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
const skillMap = ret.skills[item.system.type]; const skillMap = ret.skills[item.system.type];
@ -547,6 +567,7 @@ export class M5Character extends Actor {
if (!skip?.spells) { if (!skip?.spells) {
context.items context.items
?.filter((item) => item.type === "spell") ?.filter((item) => item.type === "spell")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();
@ -561,6 +582,7 @@ export class M5Character extends Actor {
if (!skip?.kampfkuenste) { if (!skip?.kampfkuenste) {
context.items context.items
?.filter((item) => item.type === "kampfkunst") ?.filter((item) => item.type === "kampfkunst")
.sort((a, b) => a?.sort - b?.sort)
.forEach((item) => { .forEach((item) => {
item.prepareDerivedData(); item.prepareDerivedData();

View File

@ -11,7 +11,13 @@ export default class M5CharacterSheet extends ActorSheet {
width: 1000, width: 1000,
height: 800, height: 800,
classes: ["midgard5", "sheet", "character"], classes: ["midgard5", "sheet", "character"],
tabs: [{ navSelector: ".sheet-navigation", contentSelector: ".sheet-content", initial: "base_values" }], tabs: [
{
navSelector: ".sheet-navigation",
contentSelector: ".sheet-content",
initial: "base_values",
},
],
}); });
} }
@ -68,28 +74,17 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".roll-attribute-button").on("click", async (event) => { html.find(".roll-attribute-button").on("click", async (event) => {
let elem = event.target; let target = event.target.closest("[data-attribute]") as HTMLElement;
let attributeStr = elem.dataset["attribute"]; let attributeValue = target ? parseInt(target.dataset.value) : null;
while (!attributeStr) { let attributeStr = target ? target.dataset.attribute : null;
elem = elem.parentElement;
if (!elem) return;
attributeStr = elem.dataset["attribute"];
}
const attributeValue = parseInt(elem.dataset["value"]);
const roll = M5Roll.fromAttributeValue(this.actor, attributeStr, attributeValue); const roll = M5Roll.fromAttributeValue(this.actor, attributeStr, attributeValue);
//console.log("roll-attribute-button", parent, attributeStr, attributeValue, roll)
await roll.toMessage(); await roll.toMessage();
}); });
html.find(".edit-item").on("click", async (event) => { html.find(".edit-item").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -98,13 +93,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".quantity-increase").on("click", async (event) => { html.find(".quantity-increase").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -120,13 +110,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".quantity-decrease").on("click", async (event) => { html.find(".quantity-decrease").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -141,13 +126,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".roll-consumable-item").on("click", async (event) => { html.find(".roll-consumable-item").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -164,13 +144,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".item-delete").on("click", async (event) => { html.find(".item-delete").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -179,8 +154,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".roll-learned-button").on("click", async (event) => { html.find(".roll-learned-button").on("click", async (event) => {
const row = event.target.parentElement.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let skillId = row.dataset["item"]; let skillId = target ? target.dataset.itemId : null;
const actor = this.actor as any; const actor = this.actor as any;
const item = actor.items.get(skillId) as M5Item; const item = actor.items.get(skillId) as M5Item;
@ -188,8 +163,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".roll-general-button").on("click", async (event) => { html.find(".roll-general-button").on("click", async (event) => {
const row = event.target.parentElement.parentElement; let target = event.target.closest("[data-skill]") as HTMLElement;
let skillName = row.dataset["skill"]; let skillName = target ? target.dataset.skill : null;
const data = this.actor.system; const data = this.actor.system;
const unlearnedSkill = data.skills.general[skillName] as M5SkillUnlearned; const unlearnedSkill = data.skills.general[skillName] as M5SkillUnlearned;
@ -199,8 +174,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".learn-button").on("click", async (event) => { html.find(".learn-button").on("click", async (event) => {
const row = event.target.parentElement.parentElement; let target = event.target.closest("[data-skill]") as HTMLElement;
let skillName = row.dataset["skill"]; let skillName = target ? target.dataset.skill : null;
const data = this.actor.system; const data = this.actor.system;
const unlearnedSkill = data.skills.general[skillName] as M5SkillUnlearned; const unlearnedSkill = data.skills.general[skillName] as M5SkillUnlearned;
@ -268,8 +243,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".roll-weapon-button").on("click", async (event) => { html.find(".roll-weapon-button").on("click", async (event) => {
const row = event.target.parentElement.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId) as M5Item; const item = context.items.get(itemId) as M5Item;
@ -308,13 +283,8 @@ export default class M5CharacterSheet extends ActorSheet {
}); });
html.find(".change-equipped").on("click", async (event) => { html.find(".change-equipped").on("click", async (event) => {
let row = event.target.parentElement; let target = event.target.closest("[data-item-id]") as HTMLElement;
let itemId = row.dataset["item"]; let itemId = target ? target.dataset.itemId : null;
while (!itemId) {
row = row.parentElement;
if (!row) return;
itemId = row.dataset["item"];
}
const context = this.actor as any; const context = this.actor as any;
const item = context.items.get(itemId); const item = context.items.get(itemId);
@ -323,6 +293,7 @@ export default class M5CharacterSheet extends ActorSheet {
equipped: !item.system.equipped, equipped: !item.system.equipped,
}, },
}); });
this.render(); this.render();
}); });
@ -365,28 +336,36 @@ export default class M5CharacterSheet extends ActorSheet {
const data = this.actor.system; const data = this.actor.system;
const character = this.actor as M5Character; const character = this.actor as M5Character;
character.createItem((game as Game).i18n.localize("TYPES.Item.innate-ability"), M5ItemType.SKILL, { type: M5SkillType.INNATE }); character.createItem((game as Game).i18n.localize("midgard5.innate-ability"), M5ItemType.SKILL, {
type: M5SkillType.INNATE,
});
}); });
html.find(".add-general-skill").on("click", async (event) => { html.find(".add-general-skill").on("click", async (event) => {
const data = this.actor.system; const data = this.actor.system;
const character = this.actor as M5Character; const character = this.actor as M5Character;
character.createItem((game as Game).i18n.localize("TYPES.Item.skill"), M5ItemType.SKILL, { type: M5SkillType.GENERAL }); character.createItem((game as Game).i18n.localize("TYPES.Item.skill"), M5ItemType.SKILL, {
type: M5SkillType.GENERAL,
});
}); });
html.find(".add-combat-skill").on("click", async (event) => { html.find(".add-combat-skill").on("click", async (event) => {
const data = this.actor.system; const data = this.actor.system;
const character = this.actor as M5Character; const character = this.actor as M5Character;
character.createItem((game as Game).i18n.localize("TYPES.Item.weapon-skill"), M5ItemType.SKILL, { type: M5SkillType.COMBAT }); character.createItem((game as Game).i18n.localize("midgard5.weapon-skill"), M5ItemType.SKILL, {
type: M5SkillType.COMBAT,
});
}); });
html.find(".add-language-skill").on("click", async (event) => { html.find(".add-language-skill").on("click", async (event) => {
const data = this.actor.system; const data = this.actor.system;
const character = this.actor as M5Character; const character = this.actor as M5Character;
character.createItem((game as Game).i18n.localize("TYPES.Item.language"), M5ItemType.SKILL, { type: M5SkillType.LANGUAGE }); character.createItem((game as Game).i18n.localize("midgard5.language"), M5ItemType.SKILL, {
type: M5SkillType.LANGUAGE,
});
}); });
html.find(".add-spell").on("click", async (event) => { html.find(".add-spell").on("click", async (event) => {
@ -467,9 +446,15 @@ export default class M5CharacterSheet extends ActorSheet {
// Drag & Drop // Drag & Drop
const dragDrop = new DragDrop({ const dragDrop = new DragDrop({
dragSelector: ".items-list .item", dragSelector: ".items-list .item",
dropSelector: ".sheet-body", dropSelector: null,
permissions: { dragstart: this._canDragStart.bind(this), drop: this._canDragDrop.bind(this) }, permissions: {
callbacks: { dragstart: this._onTransferItemDragStart.bind(this), drop: this._onTransferItemDrop.bind(this) }, dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
},
callbacks: {
dragstart: this._onTransferItemDragStart.bind(this),
drop: this._onTransferItemDrop.bind(this),
},
}); });
dragDrop.bind(html[0]); dragDrop.bind(html[0]);
} }
@ -479,16 +464,14 @@ export default class M5CharacterSheet extends ActorSheet {
} }
_canDragDrop(selector) { _canDragDrop(selector) {
return true; return this.options.editable;
} }
_onTransferItemDragStart(event) { _onTransferItemDragStart(event) {
const li = event.currentTarget; const li = event.target;
$(event.currentTarget).attr("data-item-actorid", this.actor.id); $(event.target).attr("data-item-actorid", this.actor.id);
const item = this.actor.items.get(li.dataset.itemId); const item = this.actor.items.get(li.dataset.itemId);
// limit transfer on personal weapons/armour/gear
if (["skill", "item", "weapon", "defensiveWeapon", "armor", "spell", "effect", "kampfkunst", "container"].includes(item.type)) {
const dragData = { const dragData = {
type: "Transfer", type: "Transfer",
actorId: this.actor.id, actorId: this.actor.id,
@ -499,9 +482,6 @@ export default class M5CharacterSheet extends ActorSheet {
if (this.actor.isToken) dragData.tokenId = this.actor.token.id; if (this.actor.isToken) dragData.tokenId = this.actor.token.id;
event.dataTransfer.setData("text/plain", JSON.stringify(dragData)); event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
} else {
return false;
}
} }
async _onTransferItemDrop(event) { async _onTransferItemDrop(event) {
@ -509,6 +489,7 @@ export default class M5CharacterSheet extends ActorSheet {
let data = null; let data = null;
try { try {
data = JSON.parse(event.dataTransfer.getData("text/plain")); data = JSON.parse(event.dataTransfer.getData("text/plain"));
data.data.system.containerId = ""; //Clean containerId
if (data.type !== "Transfer") return false; if (data.type !== "Transfer") return false;
} catch (err) { } catch (err) {
return false; return false;
@ -516,8 +497,12 @@ export default class M5CharacterSheet extends ActorSheet {
if (!data.data) return false; if (!data.data) return false;
if (data.actorId === this.actor.id) return false; if (data.actorId === this.actor.id) {
return this._onSortItem(event, data.data);
}
// limit transfer on personal weapons/armour/gear
if (["item", "weapon", "defensiveWeapon", "armor", "container"].includes(data.data.type)) {
try { try {
this.actor.createEmbeddedDocuments("Item", [duplicate(data.data)]); // Create a new Item this.actor.createEmbeddedDocuments("Item", [duplicate(data.data)]); // Create a new Item
const actor = (game as any).actors.get(data.actorId); const actor = (game as any).actors.get(data.actorId);
@ -526,6 +511,10 @@ export default class M5CharacterSheet extends ActorSheet {
console.error("Error transfering item between actors", e); console.error("Error transfering item between actors", e);
return false; return false;
} }
} else {
ui.notifications.warn("Nur Gegenstände können übertragen werden.");
return false;
}
return true; return true;
} }

View File

@ -1,195 +1,174 @@
import { M5Item } from "../items/M5Item" import { M5Item } from "../items/M5Item";
import { M5Attributes, M5ItemMod, M5ModOperation, M5ModType, M5RollTemplate } from "../M5Base" import { M5Attributes, M5ItemMod, M5ModOperation, M5ModType, M5RollTemplate } from "../M5Base";
export class M5ItemSheet extends ItemSheet { export class M5ItemSheet extends ItemSheet {
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
width: 640, width: 640,
height: 480, height: 480,
classes: ["midgard5", "sheet", "item"] classes: ["midgard5", "sheet", "item"],
}) });
} }
get template() { get template() {
//console.log("M5ItemSheet", this.item.data.type) //console.log("M5ItemSheet", this.item.data.type)
const path = "systems/midgard5/templates/sheets/item" const path = "systems/midgard5/templates/sheets/item";
return `${path}/${this.item.type}.hbs` return `${path}/${this.item.type}.hbs`;
} }
override getData(options?: Partial<ItemSheet.Options>): ItemSheet.Data<ItemSheet.Options> | Promise<ItemSheet.Data<ItemSheet.Options>> { override getData(options?: Partial<ItemSheet.Options>): ItemSheet.Data<ItemSheet.Options> | Promise<ItemSheet.Data<ItemSheet.Options>> {
const item = this.item as M5Item const item = this.item as M5Item;
return Promise.resolve(super.getData()).then(value => { return Promise.resolve(super.getData()).then((value) => {
item.prepareDerivedData() item.prepareDerivedData();
const context = value as any const context = value as any;
// Use a safe clone of the item data for further operations. // Use a safe clone of the item data for further operations.
const itemData = context.item const itemData = context.item;
// Retrieve the roll data for TinyMCE editors. // Retrieve the roll data for TinyMCE editors.
context.rollData = {} context.rollData = {};
let actor = this.object?.parent ?? null let actor = this.object?.parent ?? null;
if (actor) { if (actor) {
context.rollData = actor.getRollData() context.rollData = actor.getRollData();
} }
context.data = itemData.system context.data = itemData.system;
context.flags = itemData.flags context.flags = itemData.flags;
return context return context;
}) });
} }
override activateListeners(html: JQuery) { override activateListeners(html: JQuery) {
super.activateListeners(html) super.activateListeners(html);
html.find(".add-mod").on("click", async (event) => { html.find(".add-mod").on("click", async (event) => {
const context = this.object const context = this.object;
const mods = context.system.mods const mods = context.system.mods;
const modIndex = Object.keys(mods).length const modIndex = Object.keys(mods).length;
mods[modIndex.toString()] = { mods[modIndex.toString()] = {
type: M5ModType.ATTRIBUTE, type: M5ModType.ATTRIBUTE,
id: M5Attributes.ST, id: M5Attributes.ST,
operation: M5ModOperation.ADD, operation: M5ModOperation.ADD,
value: 0 value: 0,
} as M5ItemMod } as M5ItemMod;
this.object.update({ this.object.update({
data: { data: {
mods: mods mods: mods,
} },
}) });
}) });
html.find(".item-delete").on("click", async (event) => { html.find(".mod-delete").on("click", async (event) => {
let row = event.target.parentElement let target = event.target.closest("[data-mod-id]") as HTMLElement;
let itemId = row.dataset["item"] let modId = target ? target.dataset.modId : null;
while (!itemId) {
row = row.parentElement
if (!row)
return
itemId = row.dataset["item"]
}
const context = this.item const context = this.item;
const item = context.items.get(itemId) delete context.system.mods[modId];
item.delete() this.render(false);
this.render(false) });
})
html.find(".roll-delete").on("click", async (event) => { html.find(".roll-delete").on("click", async (event) => {
//console.log("roll-delete", this.item.data.data.rolls.formulas) let target = event.target.closest("[data-roll]") as HTMLElement;
let rollIndex = target ? target.dataset.roll : null;
let row = event.target.parentElement const rolls = this.item.system.rolls.formulas;
let rollIndex = row.dataset["roll"] delete rolls[rollIndex];
while (!rollIndex) { this.render(false);
row = row.parentElement });
if (!row)
return
rollIndex = row.dataset["roll"]
}
const rolls = this.item.system.rolls.formulas
rolls[rollIndex] = null
this.item.update({
data: {
rolls: {
formulas: rolls
}
}
})
this.render(false)
})
html.find(".roll-create").on("click", async (event) => { html.find(".roll-create").on("click", async (event) => {
const rolls = this.item.system.rolls.formulas const rolls = this.item.system.rolls.formulas;
const indeces = Object.keys(rolls).map(index => parseInt(index)).sort().reverse() const indeces = Object.keys(rolls)
const index = (indeces.find(index => !!rolls[index.toString()]) ?? -1) + 1 .map((index) => parseInt(index))
console.log("roll-create", rolls, indeces, index) .sort()
.reverse();
const index = (indeces.find((index) => !!rolls[index.toString()]) ?? -1) + 1;
console.log("roll-create", rolls, indeces, index);
rolls[index.toString()] = { rolls[index.toString()] = {
formula: "1d6", formula: "1d6",
label: (game as Game).i18n.localize("midgard5.roll"), label: (game as Game).i18n.localize("midgard5.roll"),
enabled: true enabled: true,
} as M5RollTemplate } as M5RollTemplate;
this.item.update({ this.item.update({
data: { data: {
rolls: { rolls: {
formulas: rolls formulas: rolls,
} },
} },
}) });
this.render(false) this.render(false);
}) });
// Drag & Drop // Drag & Drop
if (["item"].includes(this.object.type)) { if (["item"].includes(this.object.type)) {
const itemToItemAssociation = new DragDrop({ const itemToItemAssociation = new DragDrop({
dragSelector: ".item", dragSelector: ".item",
dropSelector: null, dropSelector: ".item-list",
permissions: { dragstart: this._canDragStart.bind(this), drop: this._canDragDrop.bind(this) }, permissions: {
dragstart: this._canDragStart.bind(this),
drop: this._canDragDrop.bind(this),
},
callbacks: { drop: this._onDropItem.bind(this) }, callbacks: { drop: this._onDropItem.bind(this) },
}) });
itemToItemAssociation.bind(html[0]) itemToItemAssociation.bind(html[0]);
} }
} }
_canDragStart(selector) { _canDragStart(selector) {
console.log("M5ItemSheet._canDragStart", selector) console.log("M5ItemSheet._canDragStart", selector);
return this.options.editable && this.object.isOwner return this.options.editable && this.object.isOwner;
} }
_canDragDrop(selector) { _canDragDrop(selector) {
console.log("M5ItemSheet._canDragDrop", selector) console.log("M5ItemSheet._canDragDrop", selector);
return true return true;
} }
async _onDropItem(event) { async _onDropItem(event) {
let data let data;
const obj = this.object const obj = this.object;
const li = event.currentTarget const li = event.currentTarget;
try { try {
data = JSON.parse(event.dataTransfer.getData("text/plain")) data = JSON.parse(event.dataTransfer.getData("text/plain"));
if (data.type !== "Item") if (data.type !== "Item") return false;
return false
} catch (err) { } catch (err) {
return false return false;
} }
// Case 1 - Import from a Compendium pack // Case 1 - Import from a Compendium pack
let itemObject let itemObject;
if (data.pack) { if (data.pack) {
const compendiumObject = await (this as any).importItemFromCollection(data.pack, data.id) const compendiumObject = await (this as any).importItemFromCollection(data.pack, data.id);
itemObject = compendiumObject.data itemObject = compendiumObject.data;
} }
// Case 2 - Import from World entity // Case 2 - Import from World entity
else { else {
const originalItem = await (game as Game).items.get(data.id) const originalItem = await (game as Game).items.get(data.id);
itemObject = duplicate(originalItem) itemObject = duplicate(originalItem);
if (!itemObject) if (!itemObject) return;
return
} }
if ((itemObject.type === "mod")) { if (itemObject.type === "mod") {
let mods = obj?.system?.mods let mods = obj?.system?.mods;
if (!mods) if (!mods) mods = [];
mods = []
itemObject.id = randomID() itemObject.id = randomID();
console.log("M5ItemSheet._onDropItem", itemObject) console.log("M5ItemSheet._onDropItem", itemObject);
mods.push(itemObject) mods.push(itemObject);
obj.update({ obj.update({
data: { data: {
mods: mods mods: mods,
} },
}) });
} }
} }
async _onDragItemStart(event) { } async _onDragItemStart(event) {}
} }

View File

@ -48,10 +48,10 @@
<th class="title"><img src="/icons/svg/d20.svg" class="table-icon"></th> <th class="title"><img src="/icons/svg/d20.svg" class="table-icon"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.weapons as |item itemId|}} {{#each data.calc.gear.weapons as |item itemId|}}
{{#if item.equipped}} {{#if item.equipped}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item {{#if item.special}}highlight{{/if}}">{{item.label}}{{#if item.special}}(*){{/if}}</td> <td class="padding edit-item {{#if item.special}}highlight{{/if}}">{{item.label}}{{#if item.special}}(*){{/if}}</td>
<td class="fixed-value">{{item.calc.ew}}</td> <td class="fixed-value">{{item.calc.ew}}</td>
<td class="fixed-value">{{item.damageBase}}</td> <td class="fixed-value">{{item.damageBase}}</td>
@ -67,7 +67,7 @@
{{/if}} {{/if}}
{{/each}} {{/each}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}">
<td class="padding edit-item">{{localize "midgard5.brawl"}}</td> <td class="padding edit-item">{{localize "midgard5.brawl"}}</td>
<td class="fixed-value">{{data.calc.stats.brawlFw}}</td> <td class="fixed-value">{{data.calc.stats.brawlFw}}</td>
<td class="fixed-value">1d6 -4</td> <td class="fixed-value">1d6 -4</td>
@ -87,9 +87,9 @@
<td><a class="title add-kampfkunst"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-kampfkunst"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.kampfkuenste as |item itemId|}} {{#each data.calc.kampfkuenste as |item itemId|}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item">{{item.label}}</td> <td class="padding edit-item">{{item.label}}</td>
<td> <td>
{{#if item.isKido}} {{#if item.isKido}}
@ -147,10 +147,10 @@
<th class="title"><img src="/icons/svg/d20.svg" class="table-icon"></th> <th class="title"><img src="/icons/svg/d20.svg" class="table-icon"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.defensiveWeapons as |item itemId|}} {{#each data.calc.gear.defensiveWeapons as |item itemId|}}
{{#if item.equipped}} {{#if item.equipped}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item">{{item.label}}</td> <td class="padding edit-item">{{item.label}}</td>
<td class="fixed-value">{{item.calc.ew}}</td> <td class="fixed-value">{{item.calc.ew}}</td>
<td class="fixed-value">{{item.defenseBonus}}</td> <td class="fixed-value">{{item.defenseBonus}}</td>
@ -176,10 +176,10 @@
<th class="title center"><img src="/systems/midgard5/assets/icons/icon/battle-gear.svg" class="table-icon"></th> <th class="title center"><img src="/systems/midgard5/assets/icons/icon/battle-gear.svg" class="table-icon"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.armor as |item itemId|}} {{#each data.calc.gear.armor as |item itemId|}}
{{#if item.equipped}} {{#if item.equipped}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding">{{item.label}}</td> <td class="padding">{{item.label}}</td>
<td class="fixed-value">{{lpProtection}}</td> <td class="fixed-value">{{lpProtection}}</td>
<td class="change-equipped"> <td class="change-equipped">

View File

@ -6,9 +6,9 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.effects as |item itemId|}} {{#each data.calc.gear.effects as |item itemId|}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="items">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
{{#if item.equipped}} {{#if item.equipped}}

View File

@ -77,11 +77,11 @@
<th class="title">&nbsp;</th> <th class="title">&nbsp;</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
<tr height = 10px></tr> <tr height = 10px></tr>
{{#each ../data.calc.gear.items as |item itemId|}} {{#each ../data.calc.gear.items as |item itemId|}}
{{#if (eq item.containerId containerId)}} {{#if (eq item.containerId containerId)}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -114,7 +114,7 @@
{{/each}} {{/each}}
{{#each ../data.calc.gear.weapons as |item itemId|}} {{#each ../data.calc.gear.weapons as |item itemId|}}
{{#if (eq item.containerId containerId)}} {{#if (eq item.containerId containerId)}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -143,7 +143,7 @@
{{/each}} {{/each}}
{{#each ../data.calc.gear.defensiveWeapons as |item itemId|}} {{#each ../data.calc.gear.defensiveWeapons as |item itemId|}}
{{#if (eq item.containerId containerId)}} {{#if (eq item.containerId containerId)}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -172,7 +172,7 @@
{{/each}} {{/each}}
{{#each ../data.calc.gear.armor as |item itemId|}} {{#each ../data.calc.gear.armor as |item itemId|}}
{{#if (eq item.containerId containerId)}} {{#if (eq item.containerId containerId)}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -226,10 +226,10 @@
<td><a class="title add-container"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-container"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
<tr height = 10px></tr> <tr height = 10px></tr>
{{#each data.calc.gear.containers as |item itemId|}} {{#each data.calc.gear.containers as |item itemId|}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -274,12 +274,11 @@
<td><a class="title add-item"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-item"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
<tr height = 10px></tr> <tr height = 10px></tr>
</tr>
{{#each data.calc.gear.items as |item itemId|}} {{#each data.calc.gear.items as |item itemId|}}
{{#if (or ../data.info.showAllItems (eq item.containerId ""))}} {{#if (or ../data.info.showAllItems (eq item.containerId ""))}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding"> <td class="padding">
<span class="edit-item">{{item.label}}</span> <span class="edit-item">{{item.label}}</span>
</td> </td>
@ -330,10 +329,10 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.weapons as |item itemId|}} {{#each data.calc.gear.weapons as |item itemId|}}
{{#if (or ../data.info.showAllItems (eq item.containerId ""))}} {{#if (or ../data.info.showAllItems (eq item.containerId ""))}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item">{{item.label}}</td> <td class="padding edit-item">{{item.label}}</td>
<td style="text-align: start"> <td style="text-align: start">
{{#unless (or (eq item.value 0) (eq item.currency ""))}} {{#unless (or (eq item.value 0) (eq item.currency ""))}}
@ -374,10 +373,10 @@
<td><a class="title add-defensiveWeapon"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-defensiveWeapon"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.defensiveWeapons as |item itemId|}} {{#each data.calc.gear.defensiveWeapons as |item itemId|}}
{{#if (or ../data.info.showAllItems (eq item.containerId ""))}} {{#if (or ../data.info.showAllItems (eq item.containerId ""))}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item">{{item.label}}</td> <td class="padding edit-item">{{item.label}}</td>
<td style="text-align: start"> <td style="text-align: start">
{{#unless (or (eq item.value 0) (eq item.currency ""))}} {{#unless (or (eq item.value 0) (eq item.currency ""))}}
@ -418,10 +417,10 @@
<td><a class="title add-armor"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-armor"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.gear.armor as |item itemId|}} {{#each data.calc.gear.armor as |item itemId|}}
{{#if (or ../data.info.showAllItems (eq item.containerId ""))}} {{#if (or ../data.info.showAllItems (eq item.containerId ""))}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item">{{item.label}}</td> <td class="padding edit-item">{{item.label}}</td>
<td style="text-align: start"> <td style="text-align: start">
{{#unless (or (eq item.value 0) (eq item.currency ""))}} {{#unless (or (eq item.value 0) (eq item.currency ""))}}

View File

@ -14,9 +14,9 @@
<th><a class="title add-innate-skill"><i class="fa-regular fa-plus"></i></a></th> <th><a class="title add-innate-skill"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.skills.innate as |skill skillId|}} {{#each data.calc.skills.innate as |skill skillId|}}
<tr data-item="{{skillId}}"> <tr data-item-id="{{skillId}}" class="item">
<td class="padding edit-item">{{skill.label}}</td> <td class="padding edit-item">{{skill.label}}</td>
<td class="fixed-value">{{skill.fw}}</td> <td class="fixed-value">{{skill.fw}}</td>
<td class="fixed-value">{{skill.calc.bonus}}</td> <td class="fixed-value">{{skill.calc.bonus}}</td>
@ -25,7 +25,7 @@
<td><a class="item-delete" title="Delete Item"><i class="fas fa-trash"></i></a></td> <td><a class="item-delete" title="Delete Item"><i class="fas fa-trash"></i></a></td>
</tr> </tr>
{{/each}} {{/each}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}">
<td class="padding edit-item">{{localize "midgard5.perception"}}</td> <td class="padding edit-item">{{localize "midgard5.perception"}}</td>
<td class="fixed-value">{{data.calc.stats.perceptionFW}}</td> <td class="fixed-value">{{data.calc.stats.perceptionFW}}</td>
<td class="fixed-value">{{data.calc.stats.perception.value}}</td> <td class="fixed-value">{{data.calc.stats.perception.value}}</td>
@ -33,7 +33,7 @@
<td><button class="roll-button roll-perception-button"></button></td> <td><button class="roll-button roll-perception-button"></button></td>
<td class="fixed-value"></td> <td class="fixed-value"></td>
</tr> </tr>
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}">
<td class="padding edit-item">{{localize "midgard5.drinking"}}</td> <td class="padding edit-item">{{localize "midgard5.drinking"}}</td>
<td class="fixed-value">{{data.calc.stats.drinkingFW}}</td> <td class="fixed-value">{{data.calc.stats.drinkingFW}}</td>
<td class="fixed-value">{{data.calc.stats.drinking.value}}</td> <td class="fixed-value">{{data.calc.stats.drinking.value}}</td>
@ -59,9 +59,9 @@
<th><a class="title add-general-skill"><i class="fa-regular fa-plus"></i></a></th> <th><a class="title add-general-skill"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.skills.general as |skill skillId|}} {{#each data.calc.skills.general as |skill skillId|}}
<tr data-item="{{skillId}}"> <tr data-item-id="{{skillId}}" class="item">
<td class="padding edit-item">{{skill.label}}</td> <td class="padding edit-item">{{skill.label}}</td>
<td> <td>
<i class="fa fa-minus-circle fw-decrease" style="cursor: pointer"></i> <i class="fa fa-minus-circle fw-decrease" style="cursor: pointer"></i>
@ -93,9 +93,9 @@
<th><a class="title add-combat-skill"><i class="fa-regular fa-plus"></i></th> <th><a class="title add-combat-skill"><i class="fa-regular fa-plus"></i></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.skills.combat as |skill skillId|}} {{#each data.calc.skills.combat as |skill skillId|}}
<tr data-item="{{skillId}}"> <tr data-item-id="{{skillId}}" class="item">
<td class="padding edit-item">{{skill.label}}</td> <td class="padding edit-item">{{skill.label}}</td>
<td class="fixed-value">{{skill.fw}}</td> <td class="fixed-value">{{skill.fw}}</td>
<td class="fixed-value">{{skill.calc.bonus}}</td> <td class="fixed-value">{{skill.calc.bonus}}</td>
@ -123,9 +123,9 @@
<th><a class="title add-language-skill"><i class="fa-regular fa-plus"></i></a></th> <th><a class="title add-language-skill"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.skills.language as |skill skillId|}} {{#each data.calc.skills.language as |skill skillId|}}
<tr data-item="{{skillId}}"> <tr data-item-id="{{skillId}}" class="item">
<td class="padding edit-item">{{skill.label}}</td> <td class="padding edit-item">{{skill.label}}</td>
<td class="fixed-value">{{skill.fw}}</td> <td class="fixed-value">{{skill.fw}}</td>
<td class="fixed-value">{{skill.calc.bonus}}</td> <td class="fixed-value">{{skill.calc.bonus}}</td>

View File

@ -7,9 +7,9 @@
<td><a class="title add-spell"><i class="fa-regular fa-plus"></i></a></th> <td><a class="title add-spell"><i class="fa-regular fa-plus"></i></a></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each data.calc.spells as |item itemId|}} {{#each data.calc.spells as |item itemId|}}
<tr data-item="{{itemId}}"> <tr data-item-id="{{itemId}}" class="item">
<td class="padding edit-item"> <td class="padding edit-item">
<span>{{item.label}}</span> <span>{{item.label}}</span>
<span class="spell-process">{{localize item.process}}</span> <span class="spell-process">{{localize item.process}}</span>

View File

@ -5,11 +5,12 @@
<th></th> <th></th>
<th></th> <th></th>
<th><button class="add-mod">+</button></th> <th><button class="add-mod">+</button></th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody class="items-list">
{{#each mods as |mod modId|}} {{#each mods as |mod modId|}}
<tr> <tr data-mod-id="{{modId}}" class="item">
<td> <td>
<select class="select-mod-type" name="data.mods.{{modId}}.type" data-type="String"> <select class="select-mod-type" name="data.mods.{{modId}}.type" data-type="String">
{{#select mod.type}} {{#select mod.type}}
@ -51,6 +52,8 @@
<td> <td>
<input name="data.mods.{{modId}}.value" type="number" value="{{mod.value}}" data-dtype="Number" /> <input name="data.mods.{{modId}}.value" type="number" value="{{mod.value}}" data-dtype="Number" />
</td> </td>
<td class="fixed-value"><a class="mod-delete" title="Delete Roll"><i class="fas fa-trash"></i></a></td>
</tr> </tr>
{{/each}} {{/each}}
</tbody> </tbody>