From dd3fe0e38ee8e67e09ff78a40adcfe5fb1158511 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Fri, 22 May 2026 11:03:17 +0200 Subject: [PATCH] Implements inventory system, wip --- css/fvtt-prism-rpg.css | 192 +++++++++++++++++- lang/en.json | 11 +- .../applications/sheets/character-sheet.mjs | 119 +++++++++-- module/documents/item.mjs | 1 + module/models/armor.mjs | 1 + module/models/consumable.mjs | 1 + module/models/equipment.mjs | 1 + module/models/loot.mjs | 1 + module/models/shield.mjs | 1 + module/models/weapon.mjs | 1 + styles/character.less | 71 +++++++ styles/container.less | 11 + styles/global.less | 9 + styles/roll-dialog-modern.less | 4 +- templates/character-equipment.hbs | 47 ++++- 15 files changed, 431 insertions(+), 40 deletions(-) diff --git a/css/fvtt-prism-rpg.css b/css/fvtt-prism-rpg.css index fabed71..b6d73b2 100644 --- a/css/fvtt-prism-rpg.css +++ b/css/fvtt-prism-rpg.css @@ -54,6 +54,13 @@ i.prismrpg { font-family: var(--font-primary); font-size: calc(var(--font-size-standard) * 1); background-image: var(--background-image-base); + background-size: 100% 100%; + background-repeat: no-repeat; +} +.application.dialog.prismrpg .window-content { + background-image: var(--background-image-base); + background-size: 100% 100%; + background-repeat: no-repeat; } .application.dialog.prismrpg button:hover { background: var(--color-dark-6); @@ -737,6 +744,76 @@ i.prismrpg { font-size: 11px; padding: 4px; } +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id] { + border: 1px dashed transparent; + transition: border-color 0.15s, background 0.15s; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container[data-container-id].drag-over { + border-color: rgba(100, 150, 255, 0.7); + background: rgba(100, 150, 255, 0.12); +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-items { + margin: 2px 0 6px 28px; + display: flex; + flex-direction: column; + gap: 2px; + border-left: 2px solid rgba(0, 0, 0, 0.15); + padding-left: 8px; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item { + display: flex; + align-items: center; + gap: 6px; + padding: 2px 4px; + border-radius: 3px; + background: rgba(0, 0, 0, 0.06); +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item:hover { + background: rgba(0, 0, 0, 0.12); +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .item-img { + width: 20px; + height: 20px; + cursor: pointer; + flex-shrink: 0; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-name { + flex: 1; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-enc { + font-size: 10px; + color: #555; + min-width: 24px; + text-align: center; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .inv-container-type-badge { + font-size: 9px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: rgba(0, 0, 0, 0.45); + background: rgba(0, 0, 0, 0.07); + border-radius: 3px; + padding: 1px 4px; + flex-shrink: 0; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls { + display: flex; + gap: 4px; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-item .controls a { + font-size: 11px; + cursor: pointer; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-container-empty { + margin: 2px 0 4px 36px; + font-size: 10px; + font-style: italic; + color: rgba(0, 0, 0, 0.35); +} .prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display { display: flex; align-items: center; @@ -3775,6 +3852,105 @@ i.prismrpg { .prismrpg .character-path-content input[type="checkbox"]:checked::after { color: rgba(0, 0, 0, 0.1); } +.prismrpg .container-content { + font-family: var(--font-primary); + font-size: calc(var(--font-size-standard) * 1); + color: var(--color-dark-1); + background-image: var(--background-image-base); + background-repeat: no-repeat; + background-size: 100% 100%; + overflow: auto; +} +.prismrpg .container-content nav.tabs [data-tab] { + color: #636060; +} +.prismrpg .container-content nav.tabs [data-tab].active { + color: #252424; +} +.prismrpg .container-content input:disabled, +.prismrpg .container-content select:disabled { + background-color: rgba(0, 0, 0, 0.2); + border-color: transparent; + color: var(--color-dark-3); +} +.prismrpg .container-content input, +.prismrpg .container-content select { + height: 1.5rem; + background-color: rgba(0, 0, 0, 0.1); + border-color: var(--color-dark-6); + color: var(--color-dark-2); +} +.prismrpg .container-content input[name="name"] { + height: 2.5rem; + margin-right: 4px; + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1.2); + font-weight: bold; + border: none; +} +.prismrpg .container-content fieldset { + margin-bottom: 4px; + border-radius: 4px; +} +.prismrpg .container-content .form-fields input, +.prismrpg .container-content .form-fields select { + text-align: center; + font-size: calc(var(--font-size-standard) * 1); +} +.prismrpg .container-content .form-fields select { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); +} +.prismrpg .container-content legend { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1.2); + font-weight: bold; + letter-spacing: 1px; +} +.prismrpg .container-content .form-fields { + padding-top: 4px; +} +.prismrpg .container-content .form-group { + display: flex; + flex: 1; + flex-direction: row; +} +.prismrpg .container-content .form-group label { + align-content: center; + min-width: 10rem; + max-width: 10rem; +} +.prismrpg .container-content .form-group select, +.prismrpg .container-content .form-group input { + text-align: left; + min-width: 12rem; + max-width: 12rem; +} +.prismrpg .container-content .form-group input[type="checkbox"] { + min-width: 1.2rem; + max-width: 1.2rem; + margin-right: 0.5rem; +} +.prismrpg .container-content label { + font-family: var(--font-secondary); + font-size: calc(var(--font-size-standard) * 1); + flex: 50%; +} +.prismrpg .container-content .align-top { + align-self: flex-start; + padding: 0.1rem; + margin-right: 0.2rem; +} +.prismrpg .container-content .shift-right { + margin-left: 2rem; +} +.prismrpg .container-content .header { + display: flex; +} +.prismrpg .container-content .header img { + width: 50px; + height: 50px; +} .prismrpg .container-content .item-img { width: 64px; height: 64px; @@ -5147,15 +5323,15 @@ i.prismrpg { .prismrpg-roll-dialog-modern .checkbox-group .checkbox-label input[type="checkbox"]:checked ~ .checkbox-text i { color: #d4af37; } -.application.dialog.prismrpg .window-content { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .window-content { background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); padding: 8px; } -.application.dialog.prismrpg .dialog-buttons { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons { padding: 6px 8px; gap: 6px; } -.application.dialog.prismrpg .dialog-buttons button { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button { background: linear-gradient(135deg, #4a4a4a 0%, #6a6a6a 100%); border: 1px solid #3a3a3a; color: white; @@ -5164,19 +5340,19 @@ i.prismrpg { border-radius: 4px; transition: all 0.2s ease; } -.application.dialog.prismrpg .dialog-buttons button:hover { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button:hover { background: linear-gradient(135deg, #5a5a5a 0%, #7a7a7a 100%); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); transform: translateY(-1px); } -.application.dialog.prismrpg .dialog-buttons button.default, -.application.dialog.prismrpg .dialog-buttons button[data-button="roll"] { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default, +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"] { background: linear-gradient(135deg, #d4af37 0%, #f4cf67 100%); border-color: #b49030; color: #2a2a2a; } -.application.dialog.prismrpg .dialog-buttons button.default:hover, -.application.dialog.prismrpg .dialog-buttons button[data-button="roll"]:hover { +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button.default:hover, +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) .dialog-buttons button[data-button="roll"]:hover { background: linear-gradient(135deg, #e4bf47 0%, #ffdf77 100%); } #token-hud .hp-loss-wrap { diff --git a/lang/en.json b/lang/en.json index 326fb3f..0953230 100644 --- a/lang/en.json +++ b/lang/en.json @@ -940,12 +940,16 @@ "addContainer": "Add container", "addRacialAbility": "Add racial ability", "addAbility": "Add ability", - "excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating" + "excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating", + "assignToContainer": "Assign to container", + "removeFromContainer": "Remove from container", + "packBurden": "Pack Burden" }, "RollSavingThrow": "Roll Saving Throw", "Dialog": { "useConsumable": "Use Consumable", - "useConsumableContent": "Use one charge of {name}? ({uses} remaining)" + "useConsumableContent": "Use one charge of {name}? ({uses} remaining)", + "assignToContainer": "Assign to Container" }, "Message": { "selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.", @@ -957,7 +961,8 @@ "noWeapons": "No weapons", "noArmor": "No armor or shields", "noKits": "No kits", - "noEquipment": "No equipment" + "noEquipment": "No equipment", + "noStoredItems": "Nothing stored" }, "Miracle": { "FIELDS": { diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index c2405c3..cc05a42 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -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 `` + }).join("") + const content = `
+ +
+ +
+
` + + 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(); } diff --git a/module/documents/item.mjs b/module/documents/item.mjs index be49d58..52bbbde 100644 --- a/module/documents/item.mjs +++ b/module/documents/item.mjs @@ -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 { diff --git a/module/models/armor.mjs b/module/models/armor.mjs index 5d4caea..94aca6a 100644 --- a/module/models/armor.mjs +++ b/module/models/armor.mjs @@ -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 } diff --git a/module/models/consumable.mjs b/module/models/consumable.mjs index dd18fee..877c373 100644 --- a/module/models/consumable.mjs +++ b/module/models/consumable.mjs @@ -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 } diff --git a/module/models/equipment.mjs b/module/models/equipment.mjs index f600657..8749565 100644 --- a/module/models/equipment.mjs +++ b/module/models/equipment.mjs @@ -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({ diff --git a/module/models/loot.mjs b/module/models/loot.mjs index 850721a..ac8ec83 100644 --- a/module/models/loot.mjs +++ b/module/models/loot.mjs @@ -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 } diff --git a/module/models/shield.mjs b/module/models/shield.mjs index f388c62..fab388b 100644 --- a/module/models/shield.mjs +++ b/module/models/shield.mjs @@ -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 } diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index 51dc5c1..e04adb0 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -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 } diff --git a/styles/character.less b/styles/character.less index a094db8..3aea457 100644 --- a/styles/character.less +++ b/styles/character.less @@ -668,6 +668,77 @@ font-size: 11px; padding: 4px; } + + // Container drag-drop highlight + .inv-container[data-container-id] { + border: 1px dashed transparent; + transition: border-color 0.15s, background 0.15s; + &.drag-over { + border-color: rgba(100, 150, 255, 0.7); + background: rgba(100, 150, 255, 0.12); + } + } + + // Items nested inside a container + .inv-container-items { + margin: 2px 0 6px 28px; + display: flex; + flex-direction: column; + gap: 2px; + border-left: 2px solid rgba(0,0,0,0.15); + padding-left: 8px; + } + + .inv-container-item { + display: flex; + align-items: center; + gap: 6px; + padding: 2px 4px; + border-radius: 3px; + background: rgba(0,0,0,0.06); + &:hover { background: rgba(0,0,0,0.12); } + .item-img { + width: 20px; + height: 20px; + cursor: pointer; + flex-shrink: 0; + } + .inv-name { + flex: 1; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .inv-enc { + font-size: 10px; + color: #555; + min-width: 24px; + text-align: center; + } + .inv-container-type-badge { + font-size: 9px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: rgba(0,0,0,0.45); + background: rgba(0,0,0,0.07); + border-radius: 3px; + padding: 1px 4px; + flex-shrink: 0; + } + .controls { + display: flex; + gap: 4px; + a { font-size: 11px; cursor: pointer; } + } + } + + .inv-container-empty { + margin: 2px 0 4px 36px; + font-size: 10px; + font-style: italic; + color: rgba(0,0,0,0.35); + } } .pack-burden-fieldset { diff --git a/styles/container.less b/styles/container.less index 1674836..b2ac1ff 100644 --- a/styles/container.less +++ b/styles/container.less @@ -1,4 +1,15 @@ .container-content { + .sheet-common(); + .item-sheet-common(); + + .header { + display: flex; + img { + width: 50px; + height: 50px; + } + } + .item-img { width: 64px; height: 64px; diff --git a/styles/global.less b/styles/global.less index 0853bcf..9acc1eb 100644 --- a/styles/global.less +++ b/styles/global.less @@ -53,6 +53,15 @@ i.prismrpg { font-family: var(--font-primary); font-size: calc(var(--font-size-standard) * 1); background-image: var(--background-image-base); + background-size: 100% 100%; + background-repeat: no-repeat; + + .window-content { + background-image: var(--background-image-base); + background-size: 100% 100%; + background-repeat: no-repeat; + } + button:hover { background: var(--color-dark-6); } diff --git a/styles/roll-dialog-modern.less b/styles/roll-dialog-modern.less index ad14d0b..7a2d8e8 100644 --- a/styles/roll-dialog-modern.less +++ b/styles/roll-dialog-modern.less @@ -263,8 +263,8 @@ } } -// Dialog application styling -.application.dialog.prismrpg { +// Dialog application styling — only apply grey gradient when roll dialog content is present +.application.dialog.prismrpg:has(.prismrpg-roll-dialog-modern) { .window-content { background: linear-gradient(135deg, #f5f5f5 0%, #e0e0e0 100%); padding: 8px; diff --git a/templates/character-equipment.hbs b/templates/character-equipment.hbs index 921b3c3..408b491 100644 --- a/templates/character-equipment.hbs +++ b/templates/character-equipment.hbs @@ -35,6 +35,7 @@
{{item.name}}
{{item.system.encLoad}}
+ {{#if item.system.equipped}}{{else}}{{/if}} @@ -61,6 +62,7 @@
{{item.name}}
{{item.system.encLoad}}
+ {{#if item.system.equipped}}{{else}}{{/if}} @@ -87,6 +89,7 @@
{{item.system.uses}}/{{item.system.usesMax}}
{{item.system.encLoad}}
+ @@ -110,6 +113,7 @@
{{item.name}}
{{item.system.encLoad}}
+ {{#if item.system.equipped}}{{else}}{{/if}} @@ -135,6 +139,7 @@
{{item.name}}
{{item.system.encLoad}}
+ {{#if item.system.equipped}}{{else}}{{/if}} @@ -160,6 +165,7 @@
{{item.name}}
{{item.system.encLoad}}
+
@@ -176,22 +182,41 @@
- {{#each containers as |item|}} -
- -
{{item.name}}
-
{{item.system.packBurden}}
-
{{item.system.encLoad}}
+ {{#each containerGroups as |group|}} +
+ +
{{group.container.name}}
+
{{group.container.system.packBurden}}
+
{{group.container.system.encLoad}}
+ {{#if group.items.length}} +
+ {{#each group.items as |item|}} +
+ {{item.type}} + +
{{item.name}}
+
{{item.system.encLoad}}
+
+ + + +
+
+ {{/each}} +
+ {{else}} +
{{localize "PRISMRPG.Message.noStoredItems"}}
+ {{/if}} {{/each}} - {{#unless containers.length}}

{{localize "PRISMRPG.Message.noContainers"}}

{{/unless}} + {{#unless containerGroups.length}}

{{localize "PRISMRPG.Message.noContainers"}}

{{/unless}}