From 4ff46865c27b8d09d32286600aec42b9c4cb5538 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Tue, 19 May 2026 22:23:31 +0200 Subject: [PATCH] Implements inventory system, wip --- css/fvtt-prism-rpg.css | 247 +++++++++++++++++- lang/en.json | 125 ++++++++- module/applications/_module.mjs | 3 + .../applications/sheets/character-sheet.mjs | 98 ++++++- .../applications/sheets/consumable-sheet.mjs | 44 ++++ .../applications/sheets/container-sheet.mjs | 52 ++++ module/applications/sheets/loot-sheet.mjs | 44 ++++ module/models/_module.mjs | 5 +- module/models/character.mjs | 15 ++ module/models/consumable.mjs | 19 ++ module/models/container.mjs | 19 ++ module/models/equipment.mjs | 1 + module/models/loot.mjs | 17 ++ module/models/race.mjs | 9 + prism-rpg.mjs | 6 + styles/character-main-v2.less | 125 ++++++++- styles/character.less | 102 ++++++++ styles/consumable.less | 9 + styles/container.less | 9 + styles/fvtt-prism-rpg.less | 3 + styles/loot.less | 9 + system.json | 5 +- templates/character-equipment.hbs | 189 +++++++++++++- templates/character-main.hbs | 57 ++++ templates/character-skills.hbs | 2 + templates/consumable.hbs | 40 +++ templates/container.hbs | 58 ++++ templates/loot.hbs | 38 +++ templates/race.hbs | 2 + 29 files changed, 1317 insertions(+), 35 deletions(-) create mode 100644 module/applications/sheets/consumable-sheet.mjs create mode 100644 module/applications/sheets/container-sheet.mjs create mode 100644 module/applications/sheets/loot-sheet.mjs create mode 100644 module/models/consumable.mjs create mode 100644 module/models/container.mjs create mode 100644 module/models/loot.mjs create mode 100644 styles/consumable.less create mode 100644 styles/container.less create mode 100644 styles/loot.less create mode 100644 templates/consumable.hbs create mode 100644 templates/container.hbs create mode 100644 templates/loot.hbs diff --git a/css/fvtt-prism-rpg.css b/css/fvtt-prism-rpg.css index 923c792..fabed71 100644 --- a/css/fvtt-prism-rpg.css +++ b/css/fvtt-prism-rpg.css @@ -681,6 +681,96 @@ i.prismrpg { .prismrpg .tab.character-equipment .main-div .equipments .name { min-width: 12rem; } +.prismrpg .tab.character-equipment .main-div .inv-section { + margin-bottom: 6px; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-items { + display: flex; + flex-direction: column; + gap: 3px; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item { + display: flex; + align-items: center; + gap: 6px; + padding: 2px 4px; + border-radius: 3px; + background: rgba(255, 255, 255, 0.15); +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item:hover { + background: rgba(255, 255, 255, 0.25); +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .item-img { + width: 24px; + height: 24px; + cursor: pointer; + flex-shrink: 0; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-name { + flex: 1; + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-enc, +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-uses, +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .inv-capacity { + font-size: 11px; + color: #555; + min-width: 30px; + text-align: center; + white-space: nowrap; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .controls { + display: flex; + gap: 4px; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-item .controls a { + font-size: 12px; + cursor: pointer; +} +.prismrpg .tab.character-equipment .main-div .inv-section .inv-empty { + font-style: italic; + color: rgba(0, 0, 0, 0.4); + text-align: center; + font-size: 11px; + padding: 4px; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 0; + font-size: 13px; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-label { + font-weight: bold; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value { + font-weight: bold; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-used { + color: #e6a817; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-sep { + color: rgba(0, 0, 0, 0.4); +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-display .pack-burden-value .pack-burden-max { + color: rgba(0, 0, 0, 0.7); +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-used { + color: #e6a817; + font-weight: bold; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-sep { + color: rgba(0, 0, 0, 0.4); + margin: 0 2px; +} +.prismrpg .tab.character-equipment .main-div .pack-burden-fieldset .pack-burden-max { + color: rgba(0, 0, 0, 0.7); + font-weight: bold; +} .prismrpg .tab.character-combat .main-div { background-image: url("../assets/ui/prism_rpg_background.webp"); background-size: cover; @@ -951,6 +1041,27 @@ i.prismrpg { .prismrpg .tab.character-miracles .main-div prose-mirror.active { min-height: 150px; } +.prismrpg .inv-item.is-equipped { + background: rgba(100, 180, 100, 0.12); + border-left: 2px solid rgba(80, 160, 80, 0.6); +} +.prismrpg .inv-item .equipped-icon { + color: #5a9e6a; +} +.prismrpg .inv-item .unequipped-icon { + color: rgba(0, 0, 0, 0.25); +} +.prismrpg .burden-excess { + font-size: 0.75em; + color: #ff5c5c; + margin-left: 4px; + white-space: nowrap; +} +.prismrpg .controls a.disabled { + opacity: 0.35; + pointer-events: none; + cursor: default; +} .prismrpg .character-main-v2 { font-family: var(--font-primary); font-size: calc(var(--font-size-standard) * 1); @@ -1052,17 +1163,21 @@ i.prismrpg { align-items: start; } .prismrpg .character-main-v2 .character-left-column { - display: flex; - flex-direction: row; - gap: 12px; - align-items: flex-start; + display: grid; + grid-template-columns: 200px 1fr; + grid-template-rows: auto auto; + column-gap: 12px; + row-gap: 8px; + align-items: start; + min-width: 0; } .prismrpg .character-main-v2 .character-left-column .portrait-hp-column { display: flex; flex-direction: column; gap: 12px; width: 200px; - flex-shrink: 0; + grid-column: 1; + grid-row: 1 / 3; } .prismrpg .character-main-v2 .character-left-column .character-portrait { width: 200px; @@ -1134,9 +1249,9 @@ i.prismrpg { display: flex; flex-direction: column; gap: 6px; - flex: 1; + grid-column: 2; + grid-row: 1; min-width: 0; - max-width: 280px; } .prismrpg .character-main-v2 .character-left-column .character-attributes .attribute-shield { position: relative; @@ -1408,6 +1523,103 @@ i.prismrpg { line-height: 1.6; resize: vertical; } +.prismrpg .burden-mr-section { + display: flex; + flex-direction: row; + gap: 16px; + padding: 8px 12px; + background: rgba(0, 0, 0, 0.35); + border: 1px solid rgba(255, 255, 255, 0.35); + border-radius: 4px; + grid-column: 2; + grid-row: 2; +} +.prismrpg .burden-mr-section .burden-mr-item { + display: flex; + flex-direction: column; + gap: 3px; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-display-row { + display: flex; + align-items: center; + gap: 8px; + min-height: 22px; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-edit-row { + display: flex; + align-items: center; + gap: 3px; + flex-wrap: wrap; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-label { + font-weight: bold; + font-size: 11px; + letter-spacing: 0.05em; + min-width: 52px; + color: #fff; + cursor: default; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-group { + display: contents; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-group label { + display: none; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr .form-fields { + display: contents; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-sub-attr select { + font-size: 11px; + padding: 1px 2px; + height: 22px; + max-width: 80px; + background: rgba(0, 0, 0, 0.3); + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 3px; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-op { + font-size: 11px; + color: rgba(255, 255, 255, 0.9); + flex-shrink: 0; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-other input[type="number"] { + width: 32px; + text-align: center; + font-size: 11px; + height: 22px; + background: rgba(0, 0, 0, 0.3); + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 3px; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-total { + font-size: 18px; + font-weight: bold; + color: #ffe566; + min-width: 24px; + text-align: center; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-used-max { + display: flex; + align-items: center; + gap: 2px; + font-size: 14px; + font-weight: bold; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-used { + color: #ffe566; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-separator { + color: rgba(255, 255, 255, 0.8); +} +.prismrpg .burden-mr-section .burden-mr-item .burden-used-max .burden-max { + color: #e0e0e0; +} +.prismrpg .burden-mr-section .burden-mr-item .burden-used-max.burden-overloaded .burden-used { + color: #ff5c5c; + font-weight: bold; +} .prismrpg .character-subattributes.tab .subattributes-content { padding: 1rem; } @@ -3563,6 +3775,27 @@ i.prismrpg { .prismrpg .character-path-content input[type="checkbox"]:checked::after { color: rgba(0, 0, 0, 0.1); } +.prismrpg .container-content .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; +} +.prismrpg .consumable-content .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; +} +.prismrpg .loot-content .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; +} .prismrpg .effects-container { padding: 0.5rem; } diff --git a/lang/en.json b/lang/en.json index 9a222fa..326fb3f 100644 --- a/lang/en.json +++ b/lang/en.json @@ -244,6 +244,17 @@ }, "wis": { "label": "Wisdom" + }, + "movementRating": { + "label": "Movement Rating", + "subAttribute": { "label": "Sub-Attribute" }, + "other": { "label": "Other" }, + "reduction": { "label": "Reduction" } + }, + "burden": { + "label": "Burden", + "subAttribute": { "label": "Sub-Attribute" }, + "other": { "label": "Other" } } } }, @@ -361,6 +372,9 @@ "money": { "label": "Money unit" }, + "equipped": { + "label": "Equipped" + }, "isKit": { "label": "Is Kit?" }, @@ -523,6 +537,17 @@ "Challenges": "Challenges", "HP": "HP", "HPTemp": "Temporary Hit Points", + "movementRating": "Movement Rating", + "burdenCharacter": "Burden", + "packBurden": "Pack Burden", + "container": "Container", + "containers": "Containers", + "consumables": "Consumables", + "loot": "Loot", + "kits": "Kits", + "weapons": "Weapons", + "encLoad": "Enc. Load", + "reduction": "Reduction", "Movement": "Movement", "Saves": "Saves", "app": "APP", @@ -898,13 +923,41 @@ "skill": "Skills list", "skills": "Skills - Your character's skills and abilities", "racialAbilities": "Racial Abilities from your character's race and sub-race", - "abilities": "Abilities acquired through class, paths, or other sources" + "abilities": "Abilities acquired through class, paths, or other sources", + "movementRating": "Movement Rating (MR): 3 + Sub-Attribute + Other - Reduction", + "burdenCharacter": "Burden: Base Burden + Sub-Attribute + Other (max); Used = sum of equipped item load", + "packBurden": "Pack Burden capacity of this container", + "uses": "Remaining uses / Max uses", + "useConsumable": "Use this consumable", + "toggleEquipped": "Toggle equipped (affects Pack Burden)", + "addWeapon": "Add weapon", + "addArmor": "Add armor", + "addShield": "Add shield", + "addConsumable": "Add consumable", + "addKit": "Add kit", + "addEquipment": "Add equipment", + "addLoot": "Add loot", + "addContainer": "Add container", + "addRacialAbility": "Add racial ability", + "addAbility": "Add ability", + "excessBurden": "Equipped burden exceeds max — excess reduces Movement Rating" }, "RollSavingThrow": "Roll Saving Throw", + "Dialog": { + "useConsumable": "Use Consumable", + "useConsumableContent": "Use one charge of {name}? ({uses} remaining)" + }, "Message": { "selectCoreSkill": "You must select a Core Skill for your character. Each character chooses one Core Skill at creation.", "dropRace": "Drag and drop a Race item here", - "dropClass": "Drag and drop a Class item here" + "dropClass": "Drag and drop a Class item here", + "noContainers": "No containers in inventory", + "noConsumables": "No consumables in inventory", + "noLoot": "No loot in inventory", + "noWeapons": "No weapons", + "noArmor": "No armor or shields", + "noKits": "No kits", + "noEquipment": "No equipment" }, "Miracle": { "FIELDS": { @@ -1381,6 +1434,69 @@ "subraceAbilityDescription": { "label": "Sub-race Ability Description" }, + "notes": { + "label": "Notes" + }, + "baseBurden": { + "label": "Base Burden" + } + } + }, + "Container": { + "FIELDS": { + "packBurden": { + "label": "Pack Burden (Capacity)" + }, + "encLoad": { + "label": "Enc. Load" + }, + "cost": { + "label": "Cost" + }, + "equipped": { + "label": "Equipped" + }, + "description": { + "label": "Description" + }, + "notes": { + "label": "Notes" + } + } + }, + "Consumable": { + "FIELDS": { + "description": { + "label": "Description" + }, + "usesMax": { + "label": "Max Uses" + }, + "uses": { + "label": "Uses" + }, + "encLoad": { + "label": "Enc. Load" + }, + "cost": { + "label": "Cost" + }, + "notes": { + "label": "Notes" + } + } + }, + "Loot": { + "FIELDS": { + "description": { + "label": "Description" + }, + "encLoad": { + "label": "Enc. Load" + }, + "cost": { + "label": "Cost" + }, "notes": { "label": "Notes" } @@ -1507,7 +1623,10 @@ "weapon": "Weapon", "race": "Race", "class": "Class", - "character-path": "Character Path" + "character-path": "Character Path", + "container": "Container", + "consumable": "Consumable", + "loot": "Loot" } } } \ No newline at end of file diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index 8431b9a..c7abd41 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -13,4 +13,7 @@ export { default as PrismRPGMiracleSheet } from "./sheets/miracle-sheet.mjs" export { default as PrismRPGRaceSheet } from "./sheets/race-sheet.mjs" export { default as PrismRPGClassSheet } from "./sheets/class-sheet.mjs" export { default as PrismRPGCharacterPathSheet } from "./sheets/character-path-sheet.mjs" +export { default as PrismRPGContainerSheet } from "./sheets/container-sheet.mjs" +export { default as PrismRPGConsumableSheet } from "./sheets/consumable-sheet.mjs" +export { default as PrismRPGLootSheet } from "./sheets/loot-sheet.mjs" export { WeaponTypesConfig } from "./weapon-types-config.mjs" diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index c72fcf5..c2405c3 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -29,6 +29,9 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet { hpTempPlus: PrismRPGCharacterSheet.#onHpTempPlus, hpTempMinus: PrismRPGCharacterSheet.#onHpTempMinus, postItemToChat: PrismRPGCharacterSheet.#onPostItemToChat, + useConsumable: PrismRPGCharacterSheet.#onUseConsumable, + toggleContainerEquipped: PrismRPGCharacterSheet.#onToggleContainerEquipped, + toggleEquipped: PrismRPGCharacterSheet.#onToggleEquipped, }, } @@ -109,13 +112,39 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet { classes[1] || null, classes[2] || null ] + // Burden computed values + const bSubAttr = doc.system.burden.subAttribute + const bSubVal = doc.system.subAttributes[bSubAttr]?.value ?? 0 + const baseBurden = doc.itemTypes.race?.[0]?.system.baseBurden ?? 0 + context.burdenMax = Math.max(0, baseBurden + bSubVal + doc.system.burden.other) + // Equipped burden: only items with equipped=true count toward burden + const equippableTypes = [ + ...doc.itemTypes.weapon, + ...doc.itemTypes.armor, + ...doc.itemTypes.shield, + ...doc.itemTypes.equipment, + ...doc.itemTypes.container, + ] + const burdenEquipped = equippableTypes + .filter(i => i.system.equipped) + .reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0) + context.burdenUsed = burdenEquipped + // Excess equipped burden reduces Movement Rating + const excessBurden = Math.max(0, burdenEquipped - context.burdenMax) + // Movement Rating computed value (excess burden adds to reduction) + const mrSubAttr = doc.system.movementRating.subAttribute + const mrSubVal = doc.system.subAttributes[mrSubAttr]?.value ?? 0 + context.movementRatingValue = Math.max(0, + 3 + mrSubVal + doc.system.movementRating.other - doc.system.movementRating.reduction - excessBurden + ) + context.excessBurden = excessBurden break case "skills": context.tab = context.tabs.skills context.skills = doc.itemTypes.skill context.racialAbilities = doc.itemTypes["racial-ability"] - context.abilities = doc.itemTypes["ability"] - context.vulnerabilities = doc.itemTypes.vulnerability + context.abilities = doc.itemTypes.ability + context.vulnerabilities = doc.itemTypes.vulnerability ?? [] break case "subattributes": context.tab = context.tabs.subattributes @@ -133,7 +162,25 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet { break case "equipment": context.tab = context.tabs.equipment - context.equipments = doc.itemTypes.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, + ...doc.itemTypes.weapon, + ...doc.itemTypes.armor, + ...doc.itemTypes.shield, + ].reduce((sum, i) => sum + (i.system.encLoad ?? 0), 0) break case "biography": context.tab = context.tabs.biography @@ -237,6 +284,51 @@ export default class PrismRPGCharacterSheet extends PrismRPGActorSheet { } static async #onCreateEquipment(event, target) { + const itemType = target.dataset.itemType ?? "equipment" + const isKit = target.dataset.itemKit === "true" + const typeLabel = game.i18n.localize(`TYPES.Item.${itemType}`) || itemType + const itemData = { + name: game.i18n.format("DOCUMENT.New", { type: typeLabel }), + type: itemType, + } + if (isKit) itemData["system.isKit"] = true + await this.document.createEmbeddedDocuments("Item", [itemData]) + } + + static async #onUseConsumable(event, target) { + const itemElement = target.closest("[data-item-id]") + if (!itemElement) return + const item = this.document.items.get(itemElement.dataset.itemId) + if (!item) return + if (item.system.uses <= 0) return + + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { title: game.i18n.localize("PRISMRPG.Dialog.useConsumable") }, + content: `

${game.i18n.format("PRISMRPG.Dialog.useConsumableContent", { name: item.name, uses: item.system.uses })}

`, + }) + if (!confirmed) return + + if (item.system.uses <= 1) { + await item.delete() + } else { + await item.update({ "system.uses": item.system.uses - 1 }) + } + } + + static async #onToggleContainerEquipped(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.equipped": !item.system.equipped }) + } + + static async #onToggleEquipped(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.equipped": !item.system.equipped }) } static async #onPostItemToChat(event, target) { diff --git a/module/applications/sheets/consumable-sheet.mjs b/module/applications/sheets/consumable-sheet.mjs new file mode 100644 index 0000000..cb2cf31 --- /dev/null +++ b/module/applications/sheets/consumable-sheet.mjs @@ -0,0 +1,44 @@ +import PrismRPGItemSheet from "./base-item-sheet.mjs" + +export default class PrismRPGConsumableSheet extends PrismRPGItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["consumable"], + position: { width: 550 }, + window: { contentClasses: ["consumable-content"] }, + } + + /** @override */ + static PARTS = { + main: { template: "systems/fvtt-prism-rpg/templates/consumable.hbs" }, + } + + /** @override */ + tabGroups = { primary: "details" } + + #getTabs() { + const tabs = { + details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" }, + description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" }, + effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" }, + } + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] === v.id + v.cssClass = v.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const context = await super._prepareContext() + context.tabs = this.#getTabs() + context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true } + ) + context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.notes, { async: true } + ) + return context + } +} diff --git a/module/applications/sheets/container-sheet.mjs b/module/applications/sheets/container-sheet.mjs new file mode 100644 index 0000000..552e3f2 --- /dev/null +++ b/module/applications/sheets/container-sheet.mjs @@ -0,0 +1,52 @@ +import PrismRPGItemSheet from "./base-item-sheet.mjs" + +export default class PrismRPGContainerSheet extends PrismRPGItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["container"], + position: { + width: 600, + }, + window: { + contentClasses: ["container-content"], + }, + } + + /** @override */ + static PARTS = { + main: { + template: "systems/fvtt-prism-rpg/templates/container.hbs", + }, + } + + /** @override */ + tabGroups = { + primary: "details", + } + + #getTabs() { + const tabs = { + details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" }, + description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" }, + effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" }, + } + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] === v.id + v.cssClass = v.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const context = await super._prepareContext() + context.tabs = this.#getTabs() + context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true } + ) + context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.notes, { async: true } + ) + return context + } +} diff --git a/module/applications/sheets/loot-sheet.mjs b/module/applications/sheets/loot-sheet.mjs new file mode 100644 index 0000000..0649132 --- /dev/null +++ b/module/applications/sheets/loot-sheet.mjs @@ -0,0 +1,44 @@ +import PrismRPGItemSheet from "./base-item-sheet.mjs" + +export default class PrismRPGLootSheet extends PrismRPGItemSheet { + /** @override */ + static DEFAULT_OPTIONS = { + classes: ["loot"], + position: { width: 500 }, + window: { contentClasses: ["loot-content"] }, + } + + /** @override */ + static PARTS = { + main: { template: "systems/fvtt-prism-rpg/templates/loot.hbs" }, + } + + /** @override */ + tabGroups = { primary: "details" } + + #getTabs() { + const tabs = { + details: { id: "details", group: "primary", label: "PRISMRPG.Label.details" }, + description: { id: "description", group: "primary", label: "PRISMRPG.Label.description" }, + effects: { id: "effects", group: "primary", label: "PRISMRPG.Label.effects" }, + } + for (const v of Object.values(tabs)) { + v.active = this.tabGroups[v.group] === v.id + v.cssClass = v.active ? "active" : "" + } + return tabs + } + + /** @override */ + async _prepareContext() { + const context = await super._prepareContext() + context.tabs = this.#getTabs() + context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.description, { async: true } + ) + context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML( + this.document.system.notes, { async: true } + ) + return context + } +} diff --git a/module/models/_module.mjs b/module/models/_module.mjs index 9d49064..2a3090b 100644 --- a/module/models/_module.mjs +++ b/module/models/_module.mjs @@ -10,4 +10,7 @@ export { default as PrismRPGAbility } from "./ability.mjs" export { default as PrismRPGEquipment } from "./equipment.mjs" export { default as PrismRPGRace } from "./race.mjs" export { default as PrismRPGClass } from "./class.mjs" -export { default as PrismRPGCharacterPath } from "./character-path.mjs" \ No newline at end of file +export { default as PrismRPGCharacterPath } from "./character-path.mjs" +export { default as PrismRPGContainer } from "./container.mjs" +export { default as PrismRPGConsumable } from "./consumable.mjs" +export { default as PrismRPGLoot } from "./loot.mjs" \ No newline at end of file diff --git a/module/models/character.mjs b/module/models/character.mjs index f93c65f..29f048b 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -136,6 +136,21 @@ export default class PrismRPGCharacter extends foundry.abstract.TypeDataModel { }, {}), ) + // Sub-attribute choices for movement rating and burden selectors + const subAttributeChoices = () => + Object.values(SYSTEM.SUB_ATTRIBUTES).reduce((obj, s) => { obj[s.id] = s.label; return obj }, {}) + + schema.movementRating = new fields.SchemaField({ + subAttribute: new fields.StringField({ required: true, initial: "stamina", choices: subAttributeChoices }), + other: new fields.NumberField({ ...requiredInteger, initial: 0 }), + reduction: new fields.NumberField({ ...requiredInteger, initial: 0 }) + }) + + schema.burden = new fields.SchemaField({ + subAttribute: new fields.StringField({ required: true, initial: "vigor", choices: subAttributeChoices }), + other: new fields.NumberField({ ...requiredInteger, initial: 0 }) + }) + return schema } diff --git a/module/models/consumable.mjs b/module/models/consumable.mjs new file mode 100644 index 0000000..dd18fee --- /dev/null +++ b/module/models/consumable.mjs @@ -0,0 +1,19 @@ +export default class PrismRPGConsumable extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields + const requiredInteger = { required: true, nullable: false, integer: true } + const schema = {} + + schema.description = new fields.HTMLField({ required: true, textSearch: true }) + schema.usesMax = new fields.NumberField({ ...requiredInteger, initial: 1, min: 1 }) + schema.uses = new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }) + 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 }) + + return schema + } + + /** @override */ + static LOCALIZATION_PREFIXES = ["PRISMRPG.Consumable"] +} diff --git a/module/models/container.mjs b/module/models/container.mjs new file mode 100644 index 0000000..7f2e552 --- /dev/null +++ b/module/models/container.mjs @@ -0,0 +1,19 @@ +export default class PrismRPGContainer extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields + const requiredInteger = { required: true, nullable: false, integer: true } + const schema = {} + + schema.description = new fields.HTMLField({ required: true, textSearch: true }) + schema.packBurden = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + schema.encLoad = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + schema.cost = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + schema.equipped = new fields.BooleanField({ required: true, initial: false }) + schema.notes = new fields.HTMLField({ required: true }) + + return schema + } + + /** @override */ + static LOCALIZATION_PREFIXES = ["PRISMRPG.Container"] +} diff --git a/module/models/equipment.mjs b/module/models/equipment.mjs index 1ffe3c5..f600657 100644 --- a/module/models/equipment.mjs +++ b/module/models/equipment.mjs @@ -12,6 +12,7 @@ export default class PrismRPGEquipment extends foundry.abstract.TypeDataModel { schema.encLoad = new fields.NumberField({ required: true, initial: 0, min: 0 }) 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 }) // Kit properties schema.isKit = new fields.BooleanField({ diff --git a/module/models/loot.mjs b/module/models/loot.mjs new file mode 100644 index 0000000..850721a --- /dev/null +++ b/module/models/loot.mjs @@ -0,0 +1,17 @@ +export default class PrismRPGLoot extends foundry.abstract.TypeDataModel { + static defineSchema() { + const fields = foundry.data.fields + const requiredInteger = { required: true, nullable: false, integer: true } + const schema = {} + + schema.description = new fields.HTMLField({ required: true, textSearch: true }) + 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 }) + + return schema + } + + /** @override */ + static LOCALIZATION_PREFIXES = ["PRISMRPG.Loot"] +} diff --git a/module/models/race.mjs b/module/models/race.mjs index ec910d2..19feb21 100644 --- a/module/models/race.mjs +++ b/module/models/race.mjs @@ -46,6 +46,15 @@ export default class PrismRPGRace extends foundry.abstract.TypeDataModel { label: "Language" }) + schema.baseBurden = new fields.NumberField({ + required: true, + nullable: false, + integer: true, + initial: 0, + min: 0, + label: "Base Burden" + }) + // Racial Passive schema.racialPassive = new fields.StringField({ required: true, diff --git a/prism-rpg.mjs b/prism-rpg.mjs index 35b914f..98b2776 100644 --- a/prism-rpg.mjs +++ b/prism-rpg.mjs @@ -62,6 +62,9 @@ Hooks.once("init", function () { race: models.PrismRPGRace, class: models.PrismRPGClass, "character-path": models.PrismRPGCharacterPath, + container: models.PrismRPGContainer, + consumable: models.PrismRPGConsumable, + loot: models.PrismRPGLoot, } // Register sheet application classes @@ -81,6 +84,9 @@ Hooks.once("init", function () { foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGRaceSheet, { types: ["race"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGClassSheet, { types: ["class"], makeDefault: true }) foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGCharacterPathSheet, { types: ["character-path"], makeDefault: true }) + foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGContainerSheet, { types: ["container"], makeDefault: true }) + foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGConsumableSheet, { types: ["consumable"], makeDefault: true }) + foundry.documents.collections.Items.registerSheet("prismRPG", applications.PrismRPGLootSheet, { types: ["loot"], makeDefault: true }) // Status Effects — Afflictions & Imbuements CONFIG.statusEffects = [ diff --git a/styles/character-main-v2.less b/styles/character-main-v2.less index ade420c..b8f7460 100644 --- a/styles/character-main-v2.less +++ b/styles/character-main-v2.less @@ -58,17 +58,21 @@ // Left Column - Portrait, Attributes, HP .character-left-column { - display: flex; - flex-direction: row; - gap: 12px; - align-items: flex-start; + display: grid; + grid-template-columns: 200px 1fr; + grid-template-rows: auto auto; + column-gap: 12px; + row-gap: 8px; + align-items: start; + min-width: 0; .portrait-hp-column { display: flex; flex-direction: column; gap: 12px; width: 200px; - flex-shrink: 0; + grid-column: 1; + grid-row: 1 / 3; } .character-portrait { @@ -158,9 +162,9 @@ display: flex; flex-direction: column; gap: 6px; - flex: 1; + grid-column: 2; + grid-row: 1; min-width: 0; - max-width: 280px; .attribute-shield { position: relative; @@ -484,3 +488,110 @@ } } } + +// Movement Rating + Burden section +.burden-mr-section { + display: flex; + flex-direction: row; + gap: 16px; + padding: 8px 12px; + background: rgba(0, 0, 0, 0.35); + border: 1px solid rgba(255, 255, 255, 0.35); + border-radius: 4px; + grid-column: 2; + grid-row: 2; + + .burden-mr-item { + display: flex; + flex-direction: column; + gap: 3px; + + .burden-display-row { + display: flex; + align-items: center; + gap: 8px; + min-height: 22px; + } + + .burden-edit-row { + display: flex; + align-items: center; + gap: 3px; + flex-wrap: wrap; + } + + .burden-label { + font-weight: bold; + font-size: 11px; + letter-spacing: 0.05em; + min-width: 52px; + color: #fff; + cursor: default; + } + + .burden-sub-attr { + // formField helper renders a .form-group with label stacked above select. + // Flatten it so the select sits inline in the flex row. + .form-group { + display: contents; + label { display: none; } + } + .form-fields { + display: contents; + } + select { + font-size: 11px; + padding: 1px 2px; + height: 22px; + max-width: 80px; + background: rgba(0, 0, 0, 0.3); + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 3px; + } + } + + .burden-op { + font-size: 11px; + color: rgba(255, 255, 255, 0.9); + flex-shrink: 0; + } + + .burden-other { + input[type="number"] { + width: 32px; + text-align: center; + font-size: 11px; + height: 22px; + background: rgba(0, 0, 0, 0.3); + color: #fff; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 3px; + } + } + + .burden-total { + font-size: 18px; + font-weight: bold; + color: #ffe566; + min-width: 24px; + text-align: center; + } + + .burden-used-max { + display: flex; + align-items: center; + gap: 2px; + font-size: 14px; + font-weight: bold; + + .burden-used { color: #ffe566; } + .burden-separator { color: rgba(255, 255, 255, 0.8); } + .burden-max { color: #e0e0e0; } + + &.burden-overloaded { + .burden-used { color: #ff5c5c; font-weight: bold; } + } + } + } +} diff --git a/styles/character.less b/styles/character.less index 027d912..a094db8 100644 --- a/styles/character.less +++ b/styles/character.less @@ -619,6 +619,79 @@ min-width: 12rem; } } + + .inv-section { + margin-bottom: 6px; + .inv-items { + display: flex; + flex-direction: column; + gap: 3px; + } + .inv-item { + display: flex; + align-items: center; + gap: 6px; + padding: 2px 4px; + border-radius: 3px; + background: rgba(255,255,255,0.15); + &:hover { background: rgba(255,255,255,0.25); } + .item-img { + width: 24px; + height: 24px; + cursor: pointer; + flex-shrink: 0; + } + .inv-name { + flex: 1; + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .inv-enc, .inv-uses, .inv-capacity { + font-size: 11px; + color: #555; + min-width: 30px; + text-align: center; + white-space: nowrap; + } + .controls { + display: flex; + gap: 4px; + a { font-size: 12px; cursor: pointer; } + } + } + .inv-empty { + font-style: italic; + color: rgba(0,0,0,0.4); + text-align: center; + font-size: 11px; + padding: 4px; + } + } + + .pack-burden-fieldset { + .pack-burden-display { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 0; + font-size: 13px; + + .pack-burden-label { + font-weight: bold; + } + .pack-burden-value { + font-weight: bold; + .pack-burden-used { color: #e6a817; } + .pack-burden-sep { color: rgba(0,0,0,0.4); } + .pack-burden-max { color: rgba(0,0,0,0.7); } + } + } + .pack-burden-used { color: #e6a817; font-weight: bold; } + .pack-burden-sep { color: rgba(0,0,0,0.4); margin: 0 2px; } + .pack-burden-max { color: rgba(0,0,0,0.7); font-weight: bold; } + } } .tab.character-combat .main-div { @@ -911,3 +984,32 @@ min-height: 150px; } } + +// Equipped item visual feedback +.inv-item { + &.is-equipped { + background: rgba(100, 180, 100, 0.12); + border-left: 2px solid rgba(80, 160, 80, 0.6); + } + .equipped-icon { + color: #5a9e6a; + } + .unequipped-icon { + color: rgba(0, 0, 0, 0.25); + } +} + +// Burden overload warning +.burden-excess { + font-size: 0.75em; + color: #ff5c5c; + margin-left: 4px; + white-space: nowrap; +} + +// Depleted consumable button +.controls a.disabled { + opacity: 0.35; + pointer-events: none; + cursor: default; +} diff --git a/styles/consumable.less b/styles/consumable.less new file mode 100644 index 0000000..73ea18b --- /dev/null +++ b/styles/consumable.less @@ -0,0 +1,9 @@ +.consumable-content { + .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; + } +} diff --git a/styles/container.less b/styles/container.less new file mode 100644 index 0000000..1674836 --- /dev/null +++ b/styles/container.less @@ -0,0 +1,9 @@ +.container-content { + .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; + } +} diff --git a/styles/fvtt-prism-rpg.less b/styles/fvtt-prism-rpg.less index 272d947..1784db0 100644 --- a/styles/fvtt-prism-rpg.less +++ b/styles/fvtt-prism-rpg.less @@ -20,6 +20,9 @@ @import "race.less"; @import "class.less"; @import "character-path.less"; + @import "container.less"; + @import "consumable.less"; + @import "loot.less"; @import "effects.less"; @import "weapon-types-config.less"; } diff --git a/styles/loot.less b/styles/loot.less new file mode 100644 index 0000000..66972de --- /dev/null +++ b/styles/loot.less @@ -0,0 +1,9 @@ +.loot-content { + .item-img { + width: 64px; + height: 64px; + object-fit: contain; + border: 1px solid var(--color-border-light-tertiary); + border-radius: 4px; + } +} diff --git a/system.json b/system.json index 4ef195a..1db4e43 100644 --- a/system.json +++ b/system.json @@ -42,7 +42,10 @@ "equipment": { "htmlFields": ["description"] }, "race": { "htmlFields": ["description", "racialPassiveDescription", "subraceAbilityDescription", "notes"] }, "class": { "htmlFields": ["description", "attributeBonuses", "notes", "features.level1", "features.level2", "features.level3", "features.level4", "features.level5", "features.level6", "features.level7", "features.level8", "features.level9", "features.level10"] }, - "character-path": { "htmlFields": ["description"] } + "character-path": { "htmlFields": ["description"] }, + "container": { "htmlFields": ["description", "notes"] }, + "consumable": { "htmlFields": ["description", "notes"] }, + "loot": { "htmlFields": ["description", "notes"] } } }, "grid": { diff --git a/templates/character-equipment.hbs b/templates/character-equipment.hbs index 20cf09b..921b3c3 100644 --- a/templates/character-equipment.hbs +++ b/templates/character-equipment.hbs @@ -1,6 +1,16 @@
+ {{! Pack Burden Summary }} +
+ {{localize "PRISMRPG.Label.packBurden"}} +
+ {{packBurdenUsed}} + / + {{packBurdenMax}} +
+
+ {{! Money }}
{{localize "PRISMRPG.Label.money"}}
@@ -12,25 +22,178 @@
-
- {{localize "PRISMRPG.Label.equipment"}} -
- {{#each equipments as |item|}} -
+ {{! Weapons }} +
+ + {{localize "PRISMRPG.Label.weapons"}} + + +
+ {{#each weapons as |item|}} +
-
- {{item.name}} -
+
{{item.name}}
+
{{item.system.encLoad}}
{{/each}} + {{#unless weapons.length}}

{{localize "PRISMRPG.Message.noWeapons"}}

{{/unless}} +
+
+ + {{! Armor & Shields }} +
+ + {{localize "PRISMRPG.Label.armors"}} + + + +
+ {{#each armors as |item|}} +
+ +
{{item.name}}
+
{{item.system.encLoad}}
+ +
+ {{/each}} + {{#unless armors.length}}

{{localize "PRISMRPG.Message.noArmor"}}

{{/unless}} +
+
+ + {{! Consumables }} +
+ + {{localize "PRISMRPG.Label.consumables"}} + + +
+ {{#each consumables as |item|}} +
+ +
{{item.name}}
+
{{item.system.uses}}/{{item.system.usesMax}}
+
{{item.system.encLoad}}
+
+ + + +
+
+ {{/each}} + {{#unless consumables.length}}

{{localize "PRISMRPG.Message.noConsumables"}}

{{/unless}} +
+
+ + {{! Kits }} +
+ + {{localize "PRISMRPG.Label.kits"}} + + +
+ {{#each kits as |item|}} +
+ +
{{item.name}}
+
{{item.system.encLoad}}
+ +
+ {{/each}} + {{#unless kits.length}}

{{localize "PRISMRPG.Message.noKits"}}

{{/unless}} +
+
+ + {{! General Equipment (non-kit) }} +
+ + {{localize "PRISMRPG.Label.equipment"}} + + +
+ {{#each equipmentItems as |item|}} +
+ +
{{item.name}}
+
{{item.system.encLoad}}
+ +
+ {{/each}} + {{#unless equipmentItems.length}}

{{localize "PRISMRPG.Message.noEquipment"}}

{{/unless}} +
+
+ + {{! Loot }} +
+ + {{localize "PRISMRPG.Label.loot"}} + + +
+ {{#each loots as |item|}} +
+ +
{{item.name}}
+
{{item.system.encLoad}}
+
+ + +
+
+ {{/each}} + {{#unless loots.length}}

{{localize "PRISMRPG.Message.noLoot"}}

{{/unless}} +
+
+ + {{! Containers }} +
+ + {{localize "PRISMRPG.Label.containers"}} + + +
+ {{#each containers as |item|}} +
+ +
{{item.name}}
+
{{item.system.packBurden}}
+
{{item.system.encLoad}}
+ +
+ {{/each}} + {{#unless containers.length}}

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

{{/unless}}
-
\ No newline at end of file + diff --git a/templates/character-main.hbs b/templates/character-main.hbs index 0c65b2a..ec0dd65 100644 --- a/templates/character-main.hbs +++ b/templates/character-main.hbs @@ -293,6 +293,63 @@ + + {{! Movement Rating + Burden Section - below attributes }} +
+
+
+
MR
+
{{movementRatingValue}}
+
+ {{#if isEditMode}} +
+
+ {{formField + systemFields.movementRating.fields.subAttribute + value=system.movementRating.subAttribute + localize=true + }} +
+ + +
+ {{formInput systemFields.movementRating.fields.other value=system.movementRating.other}} +
+ - +
+ {{formInput systemFields.movementRating.fields.reduction value=system.movementRating.reduction}} +
+
+ {{/if}} +
+
+
+
BURDEN
+
+ {{burdenUsed}} + / + {{burdenMax}} + {{#if excessBurden}} + (-{{excessBurden}} MR) + {{/if}} +
+
+ {{#if isEditMode}} +
+
+ {{formField + systemFields.burden.fields.subAttribute + value=system.burden.subAttribute + localize=true + }} +
+ + +
+ {{formInput systemFields.burden.fields.other value=system.burden.other}} +
+
+ {{/if}} +
+
{{! Right Column - Race, Classes }} diff --git a/templates/character-skills.hbs b/templates/character-skills.hbs index 174dca8..2e70506 100644 --- a/templates/character-skills.hbs +++ b/templates/character-skills.hbs @@ -42,6 +42,7 @@
{{localize "PRISMRPG.Label.racialAbilities"}} +
{{#each racialAbilities as |item|}} @@ -64,6 +65,7 @@
{{localize "PRISMRPG.Label.abilities"}} +
{{#each abilities as |item|}} diff --git a/templates/consumable.hbs b/templates/consumable.hbs new file mode 100644 index 0000000..155d5eb --- /dev/null +++ b/templates/consumable.hbs @@ -0,0 +1,40 @@ +
+
+ + {{formInput fields.name value=source.name}} +
+ + + + {{! Details Tab }} +
+
+ {{localize "PRISMRPG.Label.consumable"}} + {{formField systemFields.usesMax value=system.usesMax localize=true}} + {{formField systemFields.uses value=system.uses localize=true}} + {{formField systemFields.encLoad value=system.encLoad localize=true}} + {{formField systemFields.cost value=system.cost localize=true}} +
+
+ + {{! Description Tab }} +
+
+ {{localize "PRISMRPG.Label.description"}} + {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
+
+ {{localize "PRISMRPG.Label.notes"}} + {{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}} +
+
+ + {{! Effects Tab }} +
+ {{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}} +
+
diff --git a/templates/container.hbs b/templates/container.hbs new file mode 100644 index 0000000..2cabda5 --- /dev/null +++ b/templates/container.hbs @@ -0,0 +1,58 @@ +
+
+ + {{formInput fields.name value=source.name}} +
+ + + + {{! Details Tab }} +
+
+ {{localize "PRISMRPG.Label.container"}} + {{formField systemFields.packBurden value=system.packBurden localize=true}} + {{formField systemFields.encLoad value=system.encLoad localize=true}} + {{formField systemFields.cost value=system.cost localize=true}} +
+
+ + {{! Description Tab }} +
+
+ {{localize "PRISMRPG.Label.description"}} + {{formInput + systemFields.description + enriched=enrichedDescription + value=system.description + name="system.description" + toggled=true + }} +
+
+ {{localize "PRISMRPG.Label.notes"}} + {{formInput + systemFields.notes + enriched=enrichedNotes + value=system.notes + name="system.notes" + toggled=true + }} +
+
+ + {{! Effects Tab }} +
+ {{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}} +
+ +
diff --git a/templates/loot.hbs b/templates/loot.hbs new file mode 100644 index 0000000..f025ef1 --- /dev/null +++ b/templates/loot.hbs @@ -0,0 +1,38 @@ +
+
+ + {{formInput fields.name value=source.name}} +
+ + + + {{! Details Tab }} +
+
+ {{localize "PRISMRPG.Label.loot"}} + {{formField systemFields.encLoad value=system.encLoad localize=true}} + {{formField systemFields.cost value=system.cost localize=true}} +
+
+ + {{! Description Tab }} +
+
+ {{localize "PRISMRPG.Label.description"}} + {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} +
+
+ {{localize "PRISMRPG.Label.notes"}} + {{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}} +
+
+ + {{! Effects Tab }} +
+ {{> systems/fvtt-prism-rpg/templates/partial-item-effects.hbs}} +
+
diff --git a/templates/race.hbs b/templates/race.hbs index fa3f072..6add46f 100644 --- a/templates/race.hbs +++ b/templates/race.hbs @@ -43,6 +43,8 @@ {{formField systemFields.language value=system.language}} + {{formField systemFields.baseBurden value=system.baseBurden}} +