Implements inventory system, wip
This commit is contained in:
@@ -32,6 +32,8 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
|
||||
useConsumable: PrismRPGCharacterSheet.#onUseConsumable,
|
||||
toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped,
|
||||
toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped,
|
||||
assignToContainer: PrismRPGCharacterSheet.#onAssignToContainer,
|
||||
removeFromContainer: PrismRPGCharacterSheet.#onRemoveFromContainer,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -162,25 +164,45 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
|
||||
break
|
||||
case "equipment":
|
||||
context.tab = context.tabs.equipment
|
||||
context.weapons = doc.itemTypes.weapon
|
||||
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield]
|
||||
context.consumables = doc.itemTypes.consumable
|
||||
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit)
|
||||
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit)
|
||||
context.loots = doc.itemTypes.loot
|
||||
context.containers = doc.itemTypes.container
|
||||
context.packBurdenMax = doc.itemTypes.container
|
||||
.filter(c => c.system.equipped)
|
||||
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
|
||||
context.packBurdenUsed = [
|
||||
...doc.itemTypes.equipment,
|
||||
...doc.itemTypes.consumable,
|
||||
...doc.itemTypes.loot,
|
||||
...doc.itemTypes.container,
|
||||
// All items that can be stored in containers
|
||||
const allStorable = [
|
||||
...doc.itemTypes.weapon,
|
||||
...doc.itemTypes.armor,
|
||||
...doc.itemTypes.shield,
|
||||
].reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
|
||||
...doc.itemTypes.equipment,
|
||||
...doc.itemTypes.consumable,
|
||||
...doc.itemTypes.loot,
|
||||
]
|
||||
// Build a map: containerId → items[]
|
||||
const containerGroups = {}
|
||||
for (const container of doc.itemTypes.container) {
|
||||
containerGroups[container.id] = { container, items: [] }
|
||||
}
|
||||
for (const item of allStorable) {
|
||||
const cid = item.system.containerId
|
||||
if (cid && containerGroups[cid]) {
|
||||
containerGroups[cid].items.push(item)
|
||||
}
|
||||
}
|
||||
context.containerGroups = Object.values(containerGroups)
|
||||
|
||||
// Items are "uncontained" if they have no containerId, or if their container was deleted
|
||||
const isUncontained = i => !i.system.containerId || !containerGroups[i.system.containerId]
|
||||
context.weapons = doc.itemTypes.weapon.filter(isUncontained)
|
||||
context.armors = [...doc.itemTypes.armor, ...doc.itemTypes.shield].filter(isUncontained)
|
||||
context.consumables = doc.itemTypes.consumable.filter(isUncontained)
|
||||
context.kits = doc.itemTypes.equipment.filter(i => i.system.isKit && isUncontained(i))
|
||||
context.equipmentItems = doc.itemTypes.equipment.filter(i => !i.system.isKit && isUncontained(i))
|
||||
context.loots = doc.itemTypes.loot.filter(isUncontained)
|
||||
context.containers = doc.itemTypes.container
|
||||
|
||||
context.packBurdenMax = doc.itemTypes.container
|
||||
.filter(c => c.system.equipped)
|
||||
.reduce((sum, c) => sum + (c.system.packBurden ?? 0), 0)
|
||||
// Pack burden = items stored in an existing container
|
||||
context.packBurdenUsed = allStorable
|
||||
.filter(i => i.system.containerId && containerGroups[i.system.containerId])
|
||||
.reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0)
|
||||
break
|
||||
case "biography":
|
||||
context.tab = context.tabs.biography
|
||||
@@ -205,6 +227,18 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
|
||||
// Handle different data types
|
||||
if (data.type === "Item") {
|
||||
const item = await fromUuid(data.uuid)
|
||||
|
||||
// Check if dropped onto a container row
|
||||
const containerEl = event.target.closest("[data-container-id]")
|
||||
if (containerEl && item?.parent === this.document) {
|
||||
const containerId = containerEl.dataset.containerId
|
||||
// Don't store containers inside containers
|
||||
if (item.type !== "container") {
|
||||
await item.update({ "system.containerId": containerId })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return this._onDropItem(item)
|
||||
}
|
||||
}
|
||||
@@ -331,6 +365,48 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
|
||||
await item.update({ "system.equipped": !item.system.equipped })
|
||||
}
|
||||
|
||||
static async #onAssignToContainer(event, target) {
|
||||
const itemElement = target.closest("[data-item-id]")
|
||||
if (!itemElement) return
|
||||
const item = this.document.items.get(itemElement.dataset.itemId)
|
||||
if (!item || item.type === "container") return
|
||||
|
||||
const containers = this.document.itemTypes.container
|
||||
if (!containers.length) {
|
||||
ui.notifications.warn(game.i18n.localize("PRISMRPG.Message.noContainers"))
|
||||
return
|
||||
}
|
||||
|
||||
const options = containers.map(c => {
|
||||
const escapedName = foundry.utils.escapeHTML(c.name)
|
||||
return `<option value="${c.id}">${escapedName}</option>`
|
||||
}).join("")
|
||||
const content = `<div class="form-group">
|
||||
<label>${game.i18n.localize("PRISMRPG.Label.container")}</label>
|
||||
<div class="form-fields">
|
||||
<select name="containerId">${options}</select>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
const containerId = await foundry.applications.api.DialogV2.prompt({
|
||||
window: { title: game.i18n.localize("PRISMRPG.Dialog.assignToContainer") },
|
||||
classes: ["prismrpg"],
|
||||
content,
|
||||
ok: {
|
||||
callback: (event, button) => button.form.elements.containerId.value,
|
||||
},
|
||||
})
|
||||
if (containerId) await item.update({ "system.containerId": containerId })
|
||||
}
|
||||
|
||||
static async #onRemoveFromContainer(event, target) {
|
||||
const itemElement = target.closest("[data-item-id]")
|
||||
if (!itemElement) return
|
||||
const item = this.document.items.get(itemElement.dataset.itemId)
|
||||
if (!item) return
|
||||
await item.update({ "system.containerId": "" })
|
||||
}
|
||||
|
||||
static async #onPostItemToChat(event, target) {
|
||||
console.log("PRISM RPG | PostItemToChat action triggered", { event: event, target: target })
|
||||
|
||||
@@ -495,6 +571,17 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet {
|
||||
this.actor.update({ "system.hp.wounds": tab });
|
||||
})
|
||||
}
|
||||
|
||||
// Container drag-over highlight
|
||||
this.element.querySelectorAll("[data-container-id]").forEach(el => {
|
||||
el.addEventListener("dragover", (e) => {
|
||||
e.preventDefault()
|
||||
el.classList.add("drag-over")
|
||||
})
|
||||
el.addEventListener("dragleave", () => el.classList.remove("drag-over"))
|
||||
el.addEventListener("drop", () => el.classList.remove("drag-over"))
|
||||
})
|
||||
|
||||
super._onRender();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export const defaultItemImg = {
|
||||
race: "systems/fvtt-prism-rpg/assets/icons/icon_race.webp",
|
||||
class: "systems/fvtt-prism-rpg/assets/icons/icon_class.webp",
|
||||
"character-path": "systems/fvtt-prism-rpg/assets/icons/icon_character_path.webp",
|
||||
container: "icons/containers/bags/pack-leather-brown.webp",
|
||||
}
|
||||
|
||||
export default class PrismRPGItem extends Item {
|
||||
|
||||
@@ -25,6 +25,7 @@ export default class PrismRPGArmor extends foundry.abstract.TypeDataModel {
|
||||
|
||||
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export default class PrismRPGConsumable extends foundry.abstract.TypeDataModel {
|
||||
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.notes = new fields.HTMLField({ required: true })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export default class PrismRPGEquipment extends foundry.abstract.TypeDataModel {
|
||||
schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
|
||||
schema.equipped = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
// Kit properties
|
||||
schema.isKit = new fields.BooleanField({
|
||||
|
||||
@@ -8,6 +8,7 @@ export default class PrismRPGLoot extends foundry.abstract.TypeDataModel {
|
||||
schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.notes = new fields.HTMLField({ required: true })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ export default class PrismRPGShield extends foundry.abstract.TypeDataModel {
|
||||
schema.cost = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
|
||||
schema.equipped = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ export default class PrismRPGWeapon extends foundry.abstract.TypeDataModel {
|
||||
schema.money = new fields.StringField({ required: true, initial: "coppercoin", choices: SYSTEM.MONEY })
|
||||
schema.equipped = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.isImplement = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.containerId = new fields.StringField({ required: false, initial: "", nullable: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user